pax_global_header00006660000000000000000000000064134317041750014517gustar00rootroot0000000000000052 comment=7be1c7c291910a0b45a978c9345c477ce3e47f12 optipng-0.7.7/000077500000000000000000000000001343170417500132125ustar00rootroot00000000000000optipng-0.7.7/AUTHORS.txt000066400000000000000000000012371343170417500151030ustar00rootroot00000000000000# OptiPNG version 0.7.7 # Copyright (C) 2001-2017 Cosmin Truta and the Contributing Authors. # See the accompanying LICENSE file for details. # # A Contributing Author is a person or company who contributed code that # is now part of OptiPNG. # # For the purpose of copyright and licensing, this is the official list # of Contributing Authors, in alphabetic order. Adam Ciarcinski Brian McQuade Elias Pipping Fabien Barbier Friedrich Preuss Maciej Pilichowski Matthew Fearnley Nelson A. de Oliveira Niels de Koning Oliver Schneider Petr Gajdos Piotr Bandurski Priit Laes Ramona C. Truta Sebastian Pipping Stefan Brns Till Maas Ville Skytt Vincent Lefvre Yuen Ho Wong optipng-0.7.7/LICENSE.txt000066400000000000000000000017701343170417500150420ustar00rootroot00000000000000Copyright (C) 2001-2017 Cosmin Truta and the Contributing Authors. For the purpose of copyright and licensing, the list of Contributing Authors is available in the accompanying AUTHORS file. This software is provided 'as-is', without any express or implied warranty. In no event will the author(s) be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, 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 notice may not be removed or altered from any source distribution. optipng-0.7.7/Makefile.in000066400000000000000000000006261343170417500152630ustar00rootroot00000000000000all: cd src/optipng && \ $(MAKE) && \ cd ../.. test: cd src/optipng && \ $(MAKE) test && \ cd ../.. check: test install: cd src/optipng && \ $(MAKE) install && \ cd ../.. uninstall: cd src/optipng && \ $(MAKE) uninstall && \ cd ../.. clean: cd src/optipng && \ $(MAKE) clean && \ cd ../.. distclean: cd src/optipng && \ $(MAKE) distclean && \ cd ../.. -rm -f src/Makefile Makefile optipng-0.7.7/README.txt000066400000000000000000000026541343170417500147170ustar00rootroot00000000000000OptiPNG version 0.7.7: Advanced PNG optimizer ============================================= Copyright and licensing ----------------------- Copyright (C) 2001-2017 Cosmin Truta and the Contributing Authors. See the accompanying AUTHORS file. This program is distributed under the zlib license. See the accompanying LICENSE file. This program uses third-party software released under various open-source licenses. Resources --------- Home page: http://optipng.sourceforge.net/ Download: http://sourceforge.net/project/showfiles.php?group_id=151404 Announcements: https://sourceforge.net/news/?group_id=151404 Support: http://sourceforge.net/tracker/?group_id=151404 ctruta (at) gmail (dot) com Build instructions ------------------ On Unix, or under a Bourne-compatible shell, run ./configure and make: cd optipng-0.7.7/ ./configure make make test Alternatively, use a pre-configured makefile that matches your compiler; e.g.: cd optipng-0.7.7/ nmake -f build/visualc.mk nmake -f build/visualc.mk test Installation instructions ------------------------- Build the program according to the instructions above. On Unix: - Make the "install" target: sudo make install - To uninstall, make the "uninstall" target: sudo make uninstall On Windows: - Copy optipng.exe to a directory found in PATH. optipng-0.7.7/build/000077500000000000000000000000001343170417500143115ustar00rootroot00000000000000optipng-0.7.7/build/bcc32.mk000066400000000000000000000005221343170417500155350ustar00rootroot00000000000000# Makefile for Borland C++ # Usage: make -f build\bcc32.mk all: cd src\optipng $(MAKE) -f build\bcc32.mk cd ..\.. test: cd src\optipng $(MAKE) -f build\bcc32.mk test cd ..\.. check: test clean: cd src\optipng $(MAKE) -f build\bcc32.mk clean cd ..\.. distclean: cd src\optipng $(MAKE) -f build\bcc32.mk distclean cd ..\.. optipng-0.7.7/build/visualc.mk000066400000000000000000000005461343170417500163150ustar00rootroot00000000000000# Makefile for Microsoft Visual C++ # Usage: nmake -f build\visualc.mk all: cd src\optipng $(MAKE) -f build\visualc.mk cd ..\.. test: cd src\optipng $(MAKE) -f build\visualc.mk test cd ..\.. check: test clean: cd src\optipng $(MAKE) -f build\visualc.mk clean cd ..\.. distclean: cd src\optipng $(MAKE) -f build\visualc.mk distclean cd ..\.. optipng-0.7.7/configure000077500000000000000000000275231343170417500151320ustar00rootroot00000000000000#!/bin/sh # Copyright (C) 2008-2017 Cosmin Truta. # # This software is distributed under the zlib license. # Please see the accompanying LICENSE file. trap "rm -f conftest* core a.out; exit 1" 1 2 3 15 LC_ALL=C export LC_ALL LANGUAGE=C export LANGUAGE prefix="${prefix-/usr/local}" exec_prefix="${exec_prefix-\$(prefix)}" bindir="${bindir-\$(exec_prefix)/bin}" mandir="${mandir-\$(prefix)/man}" man1dir="${man1dir-\$(mandir)/man1}" cc="${CC-gcc}" #cc="${CC-clang}" #cc="${CC-cc}" cflags="$CFLAGS" enable_debug=0 with_system_libpng=0 with_system_zlib=0 with_preconfigured_libpng=1 with_preconfigured_zlib=0 unique_file=src/optipng/optipng.c for arg in "$@" do case "$arg" in -- ) option="$arg" ;; --* ) option=`expr "X$arg" : 'X-\(.*\)'` ;; * ) option="$arg" ;; esac case "$arg" in *=* ) optarg=`expr "X$arg" : 'X[^=]*=\(.*\)'` ;; * ) optarg="" ;; esac case "$option" in -help | -hel | -he | -h ) echo "Usage:" echo " $0 [options]" echo "Options:" echo " -h, -help Show this help" echo "Installation directories:" echo " -prefix=PREFIX Install architecture-independent files in PREFIX" echo " [default: $prefix]" echo " -exec-prefix=EPREFIX Install architecture-dependent files in EPREFIX" echo " [default: PREFIX]" echo " -bindir=DIR Install executable in DIR [default: EPREFIX/bin]" echo " -mandir=DIR Install manual in DIR [default: PREFIX/man]" echo "Optional features:" echo " -enable-debug Enable debug build flags and run-time checks" echo "Optional packages:" echo " -with-system-libs Use all system-supplied libraries (details below)" echo " -with-system-libpng Use the system-supplied libpng" echo " [default: false]" echo " -with-system-zlib Use the system-supplied zlib" echo " [default: with-system-libpng]" echo "Environment variables:" echo " CC C compiler command" echo " LD Linker command" echo " AR Library archiver command" echo " RANLIB Library indexer/randomizer command" echo " CFLAGS C compiler flags (e.g. -O3)" echo " CPPFLAGS C preprocessor flags (e.g. -I DIR)" echo " LDFLAGS Linker flags (e.g. -L DIR)" echo " ARFLAGS Library archiver flags (e.g. rcu)" echo " LIBS Additional libraries (e.g. -lfoo)" exit 0 ;; -prefix | -prefi | -pref | -pre | -pr | -p ) prefix="$2" shift ;; -prefix=* | -prefi=* | -pref=* | -pre=* | -pr=* | -p=* ) prefix="$optarg" ;; -exec-prefix | -exec_prefix | -exec-prefi | -exec_prefi \ | -exec-pref | -exec_pref | -exec-pre | -exec_pre \ | -exec-pr | -exec_pr | -exec-p | -exec_p | exec- | -exec_ \ | -exec | -exe | -ex | -e ) exec_prefix="$2" shift ;; -exec-prefix=* | -exec_prefix=* | -exec-prefi=* | -exec_prefi=* \ | -exec-pref=* | -exec_pref=* | -exec-pre=* | -exec_pre=* \ | -exec-pr=* | -exec_pr=* | -exec-p=* | -exec_p=* | exec-=* | -exec_=* \ | -exec=* | -exe=* | -ex=* | -e=* ) exec_prefix="$optarg" ;; -bindir | -bindi | -bind | -bin | -bi | -b ) bindir="$2" shift ;; -bindir=* | -bindi=* | -bind=* | -bin=* | -bi=* | -b=* ) bindir="$optarg" ;; -mandir | -mandi | -mand | -man | -ma | -m ) mandir="$2" shift ;; -mandir=* | -mandi=* | -mand=* | -man=* | -ma=* | -m=* ) mandir="$optarg" ;; -enable-debug ) enable_debug=1 ;; -disable-debug ) enable_debug=0 ;; -with-system-libs ) with_system_libpng=1 with_system_zlib=1 ;; -without-system-libs ) with_system_zlib=0 with_system_libpng=0 ;; -with-system-libpng ) with_system_libpng=1 # Must use the system-supplied zlib with the system-supplied libpng. with_system_zlib=1 ;; -without-system-libpng ) with_system_libpng=0 ;; -with-system-zlib ) with_system_zlib=1 ;; -without-system-zlib ) with_system_zlib=0 # Can't use the system-supplied libpng without the system-supplied zlib. with_system_libpng=0 ;; * ) echo "$0: error: unknown option: $arg" echo "Type \"$0 -help\" for help" exit 64 # EX_USAGE ;; esac done if test ! -f "$0" then echo "$0: error: cannot find myself; rerun with an absolute file name" exit 1 fi if test ! -r "$unique_file" then echo "$0: error: cannot find: $unique_file" echo "$0: note: building outside the source directory tree is not supported" exit 1 fi test=conftest$$ cat > $test.c </dev/null then gccish=1 fi ;; esac rm -f $test.c $test.o if test "$gccish" -ne 0 then CC="${CC-$cc}" CFLAGS="${CFLAGS--O2 -Wall -Wextra}" else CC="${CC-cc}" CFLAGS="${CFLAGS--O}" fi if test "$enable_debug" -ne 0 then CPPFLAGS="$CPPFLAGS -DDEBUG -D_DEBUG -DPNGX_DEBUG" CFLAGS="$CFLAGS -g" LDFLAGS="$LDFLAGS -g" fi if test "$with_system_libpng" -ne 0 then USE_SYSTEM_LIBPNG_TRUE="" USE_SYSTEM_LIBPNG_FALSE="#" echo "Checking for system libpng..." test=conftest$$ cat > $test.c < #if PNG_LIBPNG_VER < 10209 #error This program requires libpng version 1.2.9 or higher #endif int dummy; EOM ($CC -c $CPPFLAGS $CFLAGS $test.c) 2>/dev/null status=$? rm -f $test.c $test.o if test $status -ne 0 then echo "$0: error: missing libpng or incorrect libpng version" echo "$0: note: libpng version 1.2.9 or higher is required" exit 1 fi else USE_SYSTEM_LIBPNG_TRUE="#" USE_SYSTEM_LIBPNG_FALSE="" if test "$with_preconfigured_libpng" -ne 0 then echo "Using pre-configured libpng..." libpng_preconfig_makefile=scripts/makefile.gcc if test ! -f "src/libpng/$libpng_preconfig_makefile" then echo "$0: warning: cannot find: src/libpng/$libpng_preconfig_makefile" with_preconfigured_libpng=0 fi fi if test "$with_preconfigured_libpng" -ne 0 then sed_preconfig_libpng="" if test "$CC" then sed_preconfig_libpng=" $sed_preconfig_libpng s|^CC *=.*|CC = $CC| " fi if test "$CFLAGS" then sed_preconfig_libpng=" $sed_preconfig_libpng s|^CFLAGS *=.*|CFLAGS = $CFLAGS| " fi if test "$CPPFLAGS" then sed_preconfig_libpng=" $sed_preconfig_libpng s|^CPPFLAGS *=.*|CPPFLAGS = $CPPFLAGS| " fi if test "$LD" then sed_preconfig_libpng=" $sed_preconfig_libpng s|^LD *=.*|LD = $LD| " fi if test "$LDFLAGS" then sed_preconfig_libpng=" $sed_preconfig_libpng s|^LDFLAGS *=.*|LDFLAGS = $LDFLAGS| " fi if test "$AR$ARFLAGS" then AR="${AR-ar}" ARFLAGS="${ARFLAGS-cru}" sed_preconfig_libpng=" $sed_preconfig_libpng s|^AR *=.*|AR = $AR| s|^ARFLAGS *=.*|ARFLAGS = $ARFLAGS| s|^AR_\([A-Z]*\) *=.*|AR_\1 = $AR $ARFLAGS| " fi if test "$RANLIB" then sed_preconfig_libpng=" $sed_preconfig_libpng s|^RANLIB *=.*|RANLIB = $RANLIB| " fi sed "$sed_preconfig_libpng" \ src/libpng/$libpng_preconfig_makefile > src/libpng/Makefile LIBPNG_MK=Makefile # The pre-configured makefiles in libpng don't do distclean. LIBPNG_DISTCLEAN="clean" LIBPNG_DISTCLEAN_XCMD="\$(RM_F) \$(LIBPNG_MK)" else echo "Configuring libpng..." (cd src/libpng && ./configure) if test $? -ne 0 then echo "$0: error: could not configure: libpng" exit 1 fi fi fi if test "$with_system_zlib" -ne 0 then USE_SYSTEM_ZLIB_TRUE="" USE_SYSTEM_ZLIB_FALSE="#" echo "Checking for system zlib..." test=conftest$$ cat > $test.c < #if ZLIB_VERNUM < 0x1210 #error This program requires zlib version 1.2.1 or higher. #endif int dummy; EOM ($CC -c $CPPFLAGS $CFLAGS $test.c) 2>/dev/null status=$? rm -f $test.c $test.o if test $status -ne 0 then echo "$0: error: missing zlib or incorrect zlib version" echo "$0: note: zlib version 1.2.1 or higher is required" exit 1 fi else USE_SYSTEM_ZLIB_TRUE="#" USE_SYSTEM_ZLIB_FALSE="" case `(uname -s) 2>/dev/null || echo unknown` in mingw* | MINGW* | windows* | WINDOWS* ) with_preconfigured_zlib=1 ZLIB_MK=win32/Makefile.gcc # This pre-configured makefile doesn't do distclean. ZLIB_DISTCLEAN=clean ;; *djgpp | *DJGPP | *dos | *DOS ) with_preconfigured_zlib=1 ZLIB_MK=msdos/Makefile.dj2 # This pre-configured makefile doesn't do distclean. ZLIB_DISTCLEAN=clean ;; * ) with_preconfigured_zlib=0 ZLIB_MK=Makefile ZLIB_DISTCLEAN=distclean esac if test "$with_preconfigured_zlib" -ne 0 then echo "Using pre-configured zlib..." if test ! -f "src/zlib/$ZLIB_MK" then echo "$0: error: cannot find: src/zlib/$ZLIB_MK" exit 1 fi else echo "Configuring zlib..." (cd src/zlib && ./configure --static) if test $? -ne 0 then echo "$0: error: could not configure: zlib" exit 1 fi fi fi sed_config=" s|@prefix@|$prefix|g s|@exec_prefix@|$exec_prefix|g s|@bindir@|$bindir|g s|@mandir@|$mandir|g s|@man1dir@|$man1dir|g s|@USE_SYSTEM_LIBPNG_FALSE@|$USE_SYSTEM_LIBPNG_FALSE|g s|@USE_SYSTEM_LIBPNG_TRUE@|$USE_SYSTEM_LIBPNG_TRUE|g s|@USE_SYSTEM_ZLIB_FALSE@|$USE_SYSTEM_ZLIB_FALSE|g s|@USE_SYSTEM_ZLIB_TRUE@|$USE_SYSTEM_ZLIB_TRUE|g s|@CC@|${CC-cc}|g s|@CFLAGS@|${CFLAGS--O}|g s|@CPP@|${CPP-\$(CC) -E}|g s|@CPPFLAGS@|${CPPFLAGS-}|g s|@LD@|${LD-\$(CC)}|g s|@LDFLAGS@|${LDFLAGS--s}|g s|@AR@|${AR-ar}|g s|@ARFLAGS@|${ARFLAGS-cru}|g s|@RANLIB@|${RANLIB-ranlib}|g s|@CP_FP@|${CP_FP-cp -f -p}|g s|@MKDIR_P@|${MKDIR_P-mkdir -p}|g s|@RM_F@|${RM_F-rm -f}|g s|@LIBM@|${LIBM--lm}|g s|@LIBPNG@|${LIBPNG--lpng}|g s|@LIBS@|${LIBS-}|g s|@LIBZ@|${LIBZ--lz}|g s|@LIBPNG_DISTCLEAN@|${LIBPNG_DISTCLEAN-distclean}|g s|@LIBPNG_DISTCLEAN_XCMD@|${LIBPNG_DISTCLEAN_XCMD-true}|g s|@LIBPNG_MK@|${LIBPNG_MK-Makefile}|g s|@LIBPNG_MK_DEF@|${LIBPNG_MK_DEF-PNGLIBCONF_H_PREBUILT=pnglibconf.h.optipng}|g s|@ZLIB_DISTCLEAN@|${ZLIB_DISTCLEAN-distclean}|g s|@ZLIB_MK@|${ZLIB_MK-Makefile}|g s|@[A-Z]*_MK@|Makefile|g s| *\$|| " for makefile in \ ./Makefile \ src/Makefile \ src/gifread/Makefile \ src/minitiff/Makefile \ src/opngreduc/Makefile \ src/optipng/Makefile \ src/optipng/man/Makefile \ src/pngxtern/Makefile \ src/pnmio/Makefile do sed "$sed_config" $makefile.in > $makefile done optipng-0.7.7/doc/000077500000000000000000000000001343170417500137575ustar00rootroot00000000000000optipng-0.7.7/doc/history.txt000066400000000000000000000410241343170417500162220ustar00rootroot00000000000000OptiPNG - Revision history ========================== Legend ------ ++ Added or improved performance-related feature (might improve compression ratio or processing speed). + Added or improved feature. - Removed feature. ! Fixed bug. !! Fixed critical bug (crash, data/metadata loss or security hazard). * Other modification (e.g. architectural improvement). Version 0.7.7 2017-dec-27 ------------- * Upgraded libpng to version 1.6.34. * Upgraded zlib to version 1.2.11-optipng. * Upgraded minitiff to version 0.2. !! Fixed a buffer overflow vulnerability in the GIF decoder. [Reported by Joonun Jang] !! Fixed an integer overflow vulnerability in the TIFF decoder. [Reported by Jaeseung Choi] ! Fixed the build on macOS High Sierra. [Reported by various users] [Fixed by Yuen Ho Wong and Friedrich Preuss] ! Fixed the build on DJGPP. * Disallowed out-of-bounds values in rangeset options. Version 0.7.6 2016-apr-03 [Released by Ramona C. Truta] ------------- * Upgraded libpng to version 1.6.21. ! Fixed an assertion failure in the image reduction code. [Fixed by upgrading libpng] !! Fixed various security-sensitive defects in the BMP decoder. [Reported by Henri Salo and Hans Jerry Illikainen] [Fixed by Ramona C. Truta] ! Fixed a benign uninitialized memory read in the GIF decoder. [Reported by Gustavo Grieco] ! Fixed a build failure occurring under the Estonian (et_EE) locale. [Reported by Sebastian Pipping] [Fixed by Priit Laes] ! Fixed a build failure occurring on Mac OS X, FreeBSD, and possibly other systems that lack POSIX-compliant high-resolution timestamps. [Reported by Ryan Schmidt and Dmitry Egorov] [Contributed by Sebastian Pipping] ! Fixed a typo causing build failures in 32-bit ANSI C compilation. [Reported by various users] Version 0.7.5 2014-mar-24 ------------- * Upgraded libpng to version 1.6.10-optipng. * Upgraded zlib to version 1.2.8-optipng. ! Fixed various build issues with libpng-1.5 and libpng-1.6. [Fixed by Oliver Schneider] * Allowed the handling of huge image files (> millions of pixels per row or column) to be independent of the libpng version. + Allowed the option -preserve to save the file ownership (UID/GID) on Unix. [Requested by Otto Keklinen] ! Fixed a build issue with Clang. + Added various enhancements to the configure script. Version 0.7.4 2012-oct-21 ------------- !! Fixed the previous fix, which failed to fix the option -fix. [Reported by Gynvael Coldwind and Mateusz Jurczyk] Version 0.7.3 2012-sep-16 ------------- !! Fixed a use-after-free vulnerability in the palette reduction code. This vulnerability was accidentally introduced in version 0.7. Version 0.7.2 2012-aug-24 ------------- * Upgraded libpng to version 1.4.12. * Upgraded zlib to version 1.2.7-optipng. ! Fixed the display of huge (4GB+) file/IDAT sizes on 32-bit platforms. ! Issued a proper error message if the output IDAT can't fit in 2GB. Acknowledged this limitation in the user manual. [Reported by John Sauter] ! Fixed the output file cleanup that should occur after a write error. * Added the option -debug and various undocumented debug features. * Moved the PNG reduction module (opngreduc) to a separate sub-project. Version 0.7.1 2012-mar-19 [Released by Ramona C. Truta] ------------- !! Fixed a regression in the reduction of palette-encoded grayscale images. (This regression was introduced in version 0.7.) [Fixed by Adam Ciarcinski] Version 0.7 2012-feb-29 [Released by Cosmin & Ramona C. Truta] ----------- * Upgraded libpng to version 1.4.9. * Upgraded zlib to version 1.2.6-optipng. !! Fixed a rarely-occurring out-of-bounds memory access error in the Z_RLE strategy in zlib. [Reported by Christopher Wichura] [Fixed by upgrading zlib] + Added the popularly-requested option -strip. The only suboption currently supported is "-strip all". + Added the option -clobber. [Contributed by Maciej Pilichowski] + Added the option -backup, as an alias of -keep. [Contributed by Ramona C. Truta] + Added the option -silent, as an alias of -quiet. [Contributed by Ramona C. Truta] - Deprecated the option -log. [Contributed by Ramona C. Truta] * Changed the activity display output from STDOUT to STDERR. + Allowed the option -preserve to save high-resolution timestamps on Unix, if the POSIX-1.2008 API is available. (This feature was previously available on Windows only.) ! Fixed a minor precision error in the display of file size percents. ! Fixed a memory leak that occurred when reading broken GIF images. ! Fixed various build issues. [Fixed by Sebastian Pipping and Ville Skytt] * Resolved all remaining compatibility issues with libpng-1.5. [Contributed by Adam Ciarcinski] * Added build support for clang. * Reorganized the source directory structure. Version 0.6.5 2011-jan-24 ------------- * Upgraded libpng to version 1.4.5-optipng. * Upgraded zlib to version 1.2.5-optipng. !! Fixed the I/O states (in libpng 1.4.5); they caused incorrect file reads in some rare cases. [Reported by Dmitry Marakasov] !! Fixed processing of PNG files with chunks of size 0. [Reported by Matthew Fearnley] ! Fixed a display error in the TIFF import. [Fixed by Piotr Bandurski] + Improved checking of the arguments of -f, -zc, -zm and -zs. - Removed quirks from the rangeset option argument syntax. ! Fixed a build issue under the system-supplied libpng-1.4. [Fixed by Petr Gajdos] * Resolved forward-compatibility issues regarding libpng-1.5; however, the system-supplied libpng-1.5 is not yet supported. * Added various enhancements to the configure+make build system. [Contributed by Elias Pipping and Dmitri Zubko] Version 0.6.4 2010-mar-14 ------------- * Upgraded libpng to version 1.4.1-optipng. * Upgraded zlib to version 1.2.4-optipng. + Added the option -nx. * Clarified the behavior of the option -nz and the relationship between the options -nz and -o0. + Added a filesystem check (resolving normalized paths, symlinks, etc.) to better detect when the output overwrites the input. + Enabled automatic wildcard expansion (i.e. globbing) on Win64. ! Fixed a Unicode build issue on Windows. [Fixed by Fabien Barbier] Version 0.6.3 2009-may-18 ------------- * Upgraded libpng to version 1.2.36-optipng. !! Fixed a use-after-free error in the GIF reader. [Reported by Roy Tam] [Fixed by Bryan McQuade] ! Flushed the output log to display the current trial in real time. This only worked on Windows in the previous version. [Fixed by Vincent Lefvre] ! Fixed an error in reporting unrecognized file formats. - Removed the requirement to "fix" TIFF files that contain unrecognized metadata. [Requested by Piotr Bandurski] * Simplified the option abbreviation rules. Option names can now be abbreviated to their shortest unique prefix, as in X11 applications. Version 0.6.2 2008-nov-09 ------------- * Upgraded libpng to version 1.2.33-optipng. ++ Put back a speed optimization, accidentally removed in version 0.6, allowing singleton trials (-o1) to be bypassed in certain conditions. !! Fixed an array overflow in the BMP reader. !! Fixed the loss of private chunks under the option -snip. + Produced a more concise on-screen output in the non-verbose mode. [Contributed by Vincent Lefvre] * Added a programming interface to the optimization engine, in order to facilitate the development of PNG-optimizing GUI apps and plugins. Version 0.6.1 2008-jul-20 ------------- * Upgraded cexcept to version 2.0.1. + Added a configure script, to be used instead of unix-secure.mak. ! Fixed a build issue that occurred when using libpng from the system. [Reported by Nelson A. de Oliveira] ! Fixed the processing when the image reduction yields an output larger than the original. [Reported by Michael Krishtopa] ! Fixed the behavior of the option -preserve. [Reported by Bill Koch] - Removed displaying of partial progress when abandoning IDATs under the option -v. (The percentages displayed were not very accurate.) Version 0.6 2008-jun-15 ----------- * Upgraded libpng to version 1.2.29-optipng. ++ Implemented grayscale(alpha)-to-palette reductions. ++ Improved conversion of bKGD info during RGB-to-palette reductions. [Contributed by Matthew Fearnley] !! Fixed conversion of bKGD and tRNS during 16-to-8-bit reductions. [Reported by Matthew Fearnley] + Added support for compressed BMP (incl. PNG-compressed BMP, you bet!) + Improved the speed of reading raw PNM files. + Recognized PNG digital signatures (dSIG) and disabled optimization in their presence, to preserve their integrity. + Allowed the user to enforce the optimization of dSIG'ed files. + Recognized APNG animation files and disabled reductions to preserve their integrity. + Added the option -snip, to allow the user to snip one image out of a multi-image file, such as animated GIF, multi-page TIFF, or APNG. + Improved recovery of PNG files with incomplete IDAT. !! Fixed a crash triggered by the use of -log on some platforms. [Fixed by Stefan Brns] ! Fixed the behavior of the options -out and -dir when the input is already optimized. [Reported by Christian Davideck] * Provided more detailed image information at the start of processing. * Provided a more detailed summary at the end of processing, under the presence of the option -v and/or the occurrence of exceptional events. Version 0.5.5 2007-jan-28 ------------- * Upgraded libpng to version 1.2.15-optipng. ++ Used a previously-missed RGB-to-palette reduction opportunity for images containing 256 distinct colors. [Reported by Joachim Kluge] !! Fixed conversion of bKGD info during RGB-to-palette reductions. [Reported by Matthew Fearnley] ! Fixed pre-computation of iterations. [Reported by Matthew Fearnley] ! Eliminated a false alarm when processing RGB images with tRNS in Unix-secure mode. [Reported by Till Maas] [Fixed by Nelson A. de Oliveira] ! Fixed the behavior of the options -out and -dir when changing interlacing. [Reported by Martin Packman] ! Fixed the behavior of "-dir [DRIVE]:" on Windows. Version 0.5.4 2006-aug-11 ------------- + Added the options -out and -dir, to specify the name of the output file or directory. [Requested by Alexander Lucas] * Added support for builds based on the system-supplied libpng. [Contributed by Nelson A. de Oliveira] Version 0.5.3 2006-jul-23 ------------- * Upgraded libpng to version 1.2.12-optipng. + Implemented basic support for TIFF (grayscale, RGB and RGBA, uncompressed). ++ Avoided the redundant trial when the search space is singular (e.g. when running "optipng -o1 example.tif"). + Prevented accidental file corruption when using the option -log. ! Fixed (again) a small typo in the online help. Version 0.5.2 2006-may-07 ------------- + Improved handling of inexact PNM-to-PNG conversions. ! Fixed a typo that was breaking the build on some Unix platforms. [Reported by Aaron Reitz] Version 0.5.1 2006-apr-30 ------------- ++ Implemented bit depth reduction for palette images. * Upgraded libpng to version 1.2.10-optipng. + Improved the BMP support. + Added a Unix man page. [Contributed by Nelson A. de Oliveira] + Allowed abbreviation of command-line options. + Changed the option -log to accept a file name as an argument. * Renamed the option -no to -simulate. ! Fixed an error in handling .bak files on Unix. [Reported by Adam Szojda and Nelson A. de Oliveira] ! Fixed a small typo in the help screen. [Reported by A. Costa and Nelson A. de Oliveira] Version 0.5 2006-jan-14 ----------- ++ Added pngxtern, a libpng add-on for external image format support: BMP (uncompressed), GIF, PNM. ++ Implemented RGB(A)-to-palette reductions. * Upgraded zlib to version 1.2.3-optipng. * Upgraded libpng to version 1.2.8-optipng. + If trials are ended prematurely, detailed progression is only reported under the option -v. - Removed reporting of some IDAT sizes that exceeded the optimum. (This was NOT a bug, but a "feature" that confused some users.) ! Fixed an RGB-to-gray reduction problem that occurred under some specific background colors. * Added support for builds based on the system-supplied zlib. [Requested by Nelson A. de Oliveira] * Modified LICENSE. It is now a verbatim spell of the zlib license. Version 0.4.8 2005-may-10 ------------- * Upgraded libpng to version 1.0.18-optipng. !! Fixed a palette-to-gray reduction problem that occurred when an RGB triple had both an alpha below max, and an alpha equal to max. [Reported by Nicolas Le Gland] + Packed the Windows executable using UPX. Version 0.4.7 2004-oct-30 ------------- !! Fixed a palette-to-gray reduction problem that occurred when having more than one alpha value per RGB triple. [Reported by Larry Hastings] ! Fixed the progress display, when processing very large images. + Displayed the image info at the beginning of processing. ++ Reduced the IDAT buffer size, allowing abandoned trials to terminate earlier in some circumstances. + Implemented error recovery, when PLTE is too small, and/or tRNS is too large. Version 0.4.6 2004-oct-25 ------------- * Upgraded zlib to version 1.2.2-optipng. * Upgraded libpng to version 1.0.17-optipng. This provides safe handling of some ill-formed PNG images. + Rewrote makefiles. + Added project workspace to build under Visual C++ 6.0, integrated with memory leak detection. ++ Implemented a premature termination of trials, in the moment when IDAT grows beyond the smallest size previously achieved. [Requested by Larry Hastings] + Changed the order of trials, to perform the trials that are more likely to yield a smaller IDAT, at the beginning. + Added the option -full to avoid the premature termination of trials; useful for debugging. Version 0.4.5 2004-may-31 ------------- * Upgraded zlib to version 1.2.1.f-cos2. * Upgraded libpng to version 1.0.15-cos2. * Renamed the option -nx to -nz. + Added the option -preserve to preserve file attributes (file mode, time stamp, etc.) where applicable. [Requested by Nehal Mistry] ! Fixed an incorrect initialization of zlib window bits. ! Displayed an error message when the search space was invalid. !! Fixed a palette reduction problem for bit depths below 8. ! Eliminated memory leaks. [Contributed by Niels de Koning] Version 0.4.4 2003-nov-20 ------------- * Upgraded zlib to version 1.2.1. ++ Added support for the Z_RLE strategy. Version 0.4.3 2003-aug-12 ------------- ! Fixed a reduction problem that caused an assertion failure. [Reported by Dimitri Papadopoulos] Version 0.4.2 2003-jun-30 ------------- ++ Enhanced the support for palette size reductions: trailing sterile palette entries are removed even when the bit depth is below 8. ! Enforced recompression when the new IDAT has the same size, but other chunks have been reduced. + Displayed the IDAT size difference as a percentage. [Requested by Nehal Mistry] Version 0.4.1 2003-may-19 ------------- ! Fixed the removal of trailing sterile palette entries. Version 0.4 2003-may-12 ----------- ++ Added support for palette-to-gray reductions. ++ Added partial support for palette size reductions. ! Fixed the reporting of invalid command-line options. ! Eliminated a spurious warning when the zlib window size is set to 256. Version 0.3.2 2003-mar-11 ------------- + Added support for updating sBIT during reductions. ! Fixed the reduction of the alpha channel. Version 0.3.1 2003-feb-25 ------------- ! Fixed the encoding of interlaced images when they become larger than the input. [Reported by James H. Cloos, Jr.] + Added the HISTORY document (this file). Version 0.3 2003-feb-24 ----------- * Announced the first public release of OptiPNG. ++ Added support for iterating through zlib memory levels. ++ Added support for collapsing IDAT, avoiding calls to png_set_compression_buffer_size(). This reduces the memory requirements. ++ Added support for lossless reduction of the image type: RGB[A] -> G[A], RGBA -> RGB, GA -> G + Added many user options. + Added documentation. Version 0.2 2001-dec-27 ----------- + Added support for optimization level presets. + Added a user option for changing the interlacing. Version 0.1 2001-dec-17 ----------- + Added support for chunk I/O status annotation. This improves the speed of OptiPNG significantly. * Added structured exception handling via cexcept. Version 0.0.1 2001-dec-10 ------------- * Introduced OptiPNG. ++ Compressed PNG IDAT data repeatedly, iterating through zlib compression and strategy levels, as well as PNG delta filters. optipng-0.7.7/doc/optipng.man.html000066400000000000000000000457331343170417500171130ustar00rootroot00000000000000 OPTIPNG

OPTIPNG


NAME

OptiPNG − Optimize Portable Network Graphics files

SYNOPSIS

optipng [−? | −h | −help]
optipng
[options...] files...

DESCRIPTION

The OptiPNG program shall attempt to optimize PNG files, i.e. reduce their size to a minimum, without losing semantic information. In addition, this program shall perform a suite of auxiliary functions like integrity checks, metadata recovery and pixmap-to-PNG conversion.

The optimization attempts are not guaranteed to succeed. Valid PNG files that cannot be optimized by this program are normally left intact; their size will not grow. The user may request to override this default behavior.

FILES

The input files are raster image files encoded either in PNG format (the native format), or in an external format. The currently supported external formats are GIF, BMP, PNM and TIFF.

OptiPNG processes each image file given in the command line as follows:

− If the image is in PNG format:

Attempts to optimize the given file in-place. If optimization is successful, or if the option −force is enabled, replaces the original file with its optimized version. The original file is backed up if the option −keep is enabled.

− If the image is in an external format:

Creates an optimized PNG version of the given file. The output file name is composed from the original file name and the .png extension.

Existing files are not overwritten, unless the option −clobber is enabled.

OPTIONS

General options
−?
, −h, −help

Show a complete summary of options.

−backup, −keep

Keep a backup of the modified files.

−clobber

Overwrite the existing output and backup files.
Under this option, if the option −backup is not enabled, the old backups of the overwritten files are deleted.

−dir directory

Write the output files to directory.

−fix

Enable error recovery. This option has no effect on valid input files.

The program will spend a reasonable amount of effort to recover as much data as possible, without increasing the output file size, but the success cannot be generally guaranteed. The program may even increase the file size, e.g., by reconstructing missing critical data. Under this option, integrity shall take precedence over file size.
When this option is not used, the invalid input files are left unprocessed.

−force

Enforce writing of a new output file.

This option overrides the program’s decision not to write such file, e.g. when the PNG input is digitally signed (using dSIG), or when the PNG output becomes larger than the PNG input.

−log file

Log messages to file. For safety reasons, file must have the extension .log.
This option is deprecated and will be removed eventually. Use shell redirection.

−out file

Write output file to file. The command line must contain exactly one input file.

−preserve

Preserve file attributes (time stamps, file access rights, etc.) where applicable.

−quiet, −silent

Run in quiet mode.
The messages are still written to the log file if the option −log is enabled.

−simulate

Run in simulation mode: perform the trials, but do not create output files.

−v

Enable the options −verbose and −version.

−verbose

Run in verbose mode.

−version

Show copyright, version and build info.

−−

Stop option switch parsing.

PNG encoding and optimization options
−o
level

Select the optimization level.
The optimization level 0 enables a set of optimization operations that require minimal effort. There will be no changes to image attributes like bit depth or color type, and no recompression of existing IDAT datastreams.
The optimization level 1 enables a single IDAT compression trial. The trial chosen is what OptiPNG thinks it’s probably the most effective.
The optimization levels 2 and higher enable multiple IDAT compression trials; the higher the level, the more trials.
The behavior and the default value of this option may change across different program versions. Use the option −h to see the details pertaining to your specific version.

−f filters

Select the PNG delta filters.
The filters argument is specified as a rangeset (e.g. −f0−5), and the default filters value depends on the optimization level set by the option −o.
The filter values 0, 1, 2, 3 and 4 indicate static filtering, and correspond to the standard PNG filter codes (None, Left, Up, Average and Paeth, respectively). The filter value 5 indicates adaptive filtering, whose effect is defined by the libpng(3) library used by OptiPNG.

−full

Produce a full report on IDAT. This option might slow down the trials.

−i type

Select the interlace type (0−1).
If the interlace type 0 is selected, the output image shall be non-interlaced (i.e. progressive-scanned). If the interlace type 1 is selected, the output image shall be interlaced using the Adam7 method.
By default, the output shall have the same interlace type as the input.

−nb

Do not apply bit depth reduction.

−nc

Do not apply color type reduction.

−np

Do not apply palette reduction.

−nx

Do not apply any lossless image reduction: enable the options −nb, −nc and −np.

−nz

Do not recode IDAT datastreams.

The IDAT optimization operations that do not require recoding (e.g. IDAT chunk concatenation) are still performed.
This option has effect on PNG input files only.

−zc levels

Select the zlib compression levels used in IDAT compression.
The levels argument is specified as a rangeset (e.g. −zc6−9), and the default levels value depends on the optimization level set by the option −o.
The effect of this option is defined by the zlib(3) library used by OptiPNG.

−zm levels

Select the zlib memory levels used in IDAT compression.
The levels argument is specified as a rangeset (e.g. −zm8−9), and the default levels value depends on the optimization level set by the option −o.
The effect of this option is defined by the zlib(3) library used by OptiPNG.

−zs strategies

Select the zlib compression strategies used in IDAT compression.
The strategies argument is specified as a rangeset (e.g. −zs0−3), and the default strategies value depends on the optimization level set by the option −o.
The effect of this option is defined by the zlib(3) library used by OptiPNG.

−zw size

Select the zlib window size (32k,16k,8k,4k,2k,1k,512,256) used in IDAT compression.
The size argument can be specified either in bytes (e.g. 16384) or kilobytes (e.g. 16k). The default size value is set to the lowest window size that yields an IDAT output as big as if yielded by the value 32768.
The effect of this option is defined by the zlib(3) library used by OptiPNG.

Editing options

−snip

Cut one image out of multi-image, animation or video files.

Depending on the input format, this may be either the first or the most relevant (e.g. the largest) image.

−strip objects

Strip metadata objects from a PNG file.
PNG metadata is the information stored in any ancillary chunk except tRNS. (tRNS represents the alpha channel, which, even if ignored in rendering, is still a proper image channel in the RGBA color space.)
The only option currently supported is −strip all.

Notes
Options may come in any order (except for −−), before, after, or alternating with file names. Option names are case-insensitive and may be abbreviated to their shortest unique prefix.

Some options may have arguments that follow the option name, separated by whitespace or the equal sign (’=’). If the option argument is a number or a rangeset, the separator may be omitted. For example:

−out newfile.png  <=>  −out=newfile.png
−o3  
<=>  −o 3  <=>  −o=3
−f0,3−5  
<=>  −f 0,3−5  <=>  −f=0,3−5

Rangeset arguments are cumulative; e.g.

−f0 −f3−5  <=>  −f0,3−5
−zs0 −zs1 −zs2−3  
<=>  −zs0,1,2,3  <=>  −zs0−3

EXTENDED DESCRIPTION

The PNG optimization algorithm consists of the following steps:

1.

Reduce the bit depth, the color type and the color palette of the image. This step may reduce the size of the uncompressed image, which, indirectly, may reduce the size of the compressed image (i.e. the size of the output PNG file).

2.

Run a suite of compression methods and strategies and select the compression parameters that yield the smallest output file.

3.

Store all IDAT contents into a single chunk, eliminating the overhead incurred by repeated IDAT headers and CRCs.

4.

Set the zlib window size inside IDAT to a mininum that does not affect the compression ratio, reducing the memory requirements of PNG decoders.

Not all of the above steps need to be executed. The behavior depends on the actual input files and user options.

Step 1 may be customized via the no-reduce options −nb, −nc, −np and −nx. Step 2 may be customized via the −o option, and may be fine-tuned via the options −zc, −zm, −zs and −zw. Step 3 is always executed. Step 4 is executed only if a new IDAT is being created, and may be fine-tuned via the option −zw.

Extremely exhaustive searches are not generally expected to yield significant improvements in compression ratio, and are recommended to advanced users only.

EXAMPLES

optipng file.png      # default speed
optipng -o5 file.png  
# slow
optipng -o7 file.png  
# very slow

BUGS

Lossless image reductions are not completely implemented. (This does not affect the integrity of the output files.) Here are the missing pieces:

− The color palette reductions are implemented only partially.
− The bit depth reductions below 8, for grayscale images, are not implemented yet.

Encoding of images whose total IDAT size exceeds 2GB is not supported.

TIFF support is limited to uncompressed, PNG-compatible (grayscale, RGB and RGBA) images.

Metadata is not imported from the external image formats.

There is no support for pipes, streams, extended file attributes or access control lists.

SEE ALSO

png(5), libpng(3), zlib(3), pngcrush(1), pngrewrite(1).

STANDARDS

The files produced by OptiPNG are compliant with PNG−2003:
Glenn Randers-Pehrson et al. Portable Network Graphics (PNG) Specification, Second Edition.
W3C Recommendation 10 November 2003; ISO/IEC IS 15948:2003 (E).
http://www.w3.org/TR/PNG/

AUTHOR

OptiPNG is written and maintained by Cosmin Truta.

This manual page was originally written by Nelson A. de Oliveira for the Debian Project. It was later updated by Cosmin Truta, and is now part of the OptiPNG distribution.


optipng-0.7.7/doc/optipng.man.pdf000066400000000000000000000317571343170417500167210ustar00rootroot00000000000000%PDF-1.2 %쏢 5 0 obj <> stream xYr#+FQC gEGf.ںAjlDŽb(˗/k~#>e?>GoWQ7g%_lvg# 'IM}8~zs89L c:OuuҘekfxmzJD` D4u `ip%4t\Wh61eF!_@4ev5yU|D}Ca~HIu]B0M( sRRAI'c!peGzDВeSc}NЎ^s4m UͪfOz?)]9ˆms=x~.rݑ||*2nl YgR_Љ'4b ym~\T6XwL(@еm>x.b$1mAXf$&C8 GSCƄm#=&WM ڈ@b: 4`;- ˄H$iځǼ cQM_4 ŒKyUnA%H7heڒ-> ({U=J]p=Pqt2c<2]WNcd3Q4T ;go_HHHtV(nS%RB"λ|eOVQH,ˇ˟/n#718(8a BV4E ZEVH>{Kf |Ћ D}߃ ;w8hP xAޥ>*qCO0 @7F<$Y`s*Q8R3I65;c`H X˼8L%y0v(8frCf5P`vm{HlU+ynV,3Eu^~Wo+֚[)u` C ~g{2D2#~Fc.Re7/S]B4l 9Ce~7V ;$ m )y~A5>Y cTF#i LԐL:+Ts`?q}1NJHD2A(+yB&ن3;}^|Ye2;Q꼓!)%e*RʜAt:PG0?nKasQ]RHo?I3J,jII*4<CWhVBm¯epǶv][zMǣ{ wDhb@J8% h&5<1S0蛋87,xۅ%D6~:'c6AX}-^vSP {pg+ȵ>#eVvn?=Y ̈́|w)dO3C'+hn;la垠Q[X X vgs7 䌹"W p/Pv,or>Z,і?OrG rtnG.b E,_Wk`hVQO4O`k7@oi_-hJUsoY*Ch~2i2n&i Us`xƘ!tzC X jɭ@mYږݜ`dp`bhE@m&O,c=ݗe )U/O'+:z! BDׁΑK[,N'4Ngq;1GZC B'&x&'wiCR^g "S88&*( e [u^c3 թyyV(Oߒ]m#NBja} -f@: jڲ)09>~N; [xFk]` lfۃ&kp4+k.SD%m"'~n Ƹ}/zPΙtOC7겗(F& ߏPE"5R&)H9ԓ֐q3\g8lxr0uNVLJJ:`C'nyx ͬ,-`C4?Yք!ᶃnnf V>s/?Gřyr6/XA_Hħ&-u|˜Ɍ65췓՚ъ-(nvRSGxtCGUm!UZ3‘L1tz CTϒXZq9 `endstream endobj 6 0 obj 2599 endobj 13 0 obj <> stream xYr}WB)rܓ'oq9:6]yCY\(1gp'e!Z+ zzO>=\0t&ō`?on|ݍyA@ r٦Rpo>m>|%o{U:o7B {`ת(2m?Uk!Y7kD;+Y5پT)NMVYjxP%kNԲJB5,[rBkj,ǵY\os^ W{:ӛQ\< mag}ϕyV0 B^1L7 ䷇DbȀYF[RmZBϵIBW)uQµy PYODZUjC*D|b mL${)ch>daɈ }I?$bmmoEdjQVHqfC' ȁWM8VgIrrd!/&(㔩vQ:>NjYrU.t(Rv8 U2+TiTÏTjR=V-1s Oi⑔8UOROD0#^*)6Ej&+N98aqD?]n!q ]Ua3Α"S(PV_pÅ/T#Mڏݑa[V6M41(!qЄG6sl;?+}r,~PM*L[}HϺW1trvdRY]uq7g|z&_71k;5ɛe`b**%Dn"A7R !yZP:XYljH1_d/*GS9/ڤ>%sЅ-V6BD.+;٣"c;k@pnRH[Uҏ-3wti[Wi3!l0Bj_ӺǸ16l~;6p]ńNT1 N:\LBDcc 04:a>$\(qӣ v&,@swZL,lEVl.baҋI*ocMXQ^vC5D}[~q7&\AtrhV2MTY랆nzo)4CWqσ1ot3$9`=2 ^=-l$S>;z-xhge _țCzPje50z9Ӣ?ÁhuM./ DA+&W)sӌdhmBA&U J}Xi6v \m ًyQ6SF=M4MɧC~ޑڲKt7G#Irj:̴I.E]YѸHh^vᤗn؍串)&vںkS*]`l~,ûa%%Fa8 iua$#Q{<$q S^w]k,cKm<~E Z 4I$ʘety5JcM\\D$n8Us7pV|g)B̶E@P׾1/+5f+W=1U.xwؑisSwk3S\⑶Td?endstream endobj 14 0 obj 2691 endobj 17 0 obj <> stream xYْ۸}H)! ĩO\J쉭<@4-1űVjs} .e?$p+_|` ~%9q}w~]8b twxo^]-ՒRd\vQ}-Oeb[U^O$,'dEx/>jV5<7',^("Dda4Y'O]n(̥\{Quꚤ+R1iҲBn2EkEʃ~T*:jr_l tk0Jff4b1l=uXSwE 縑UY59t^eZ3t ѥ$}˄'TX[53FpƢ&Zmqo^,҂ł: 83a$E^Hh?hYT~NI*YU"G}g}< ]-W íqP[y̚2~~Xw{ʑ؋GA!1GT>@!|gV` qXws1@Z]yaQ_R 1O[[ fAB\cH5W 9*Y؜wB:\-47L%XYqD> 8/{#Jc52RK҃/)zofz=&i9!@ #8O t+x(J?QE=KH(̧pCmmOkmeqdiZ\Zܘ &{b`Gy3N ^@W\gT?%BpK75jhp>-x%yEϬ P1G2ХzC1{qltޤ{+ݵ@!Q&/Z+y啟i;!v_l~6̿~:iј%S<ҹREnӭ*(!hP/M1:駝lVsyґ^Zs^zTLj2RQ苁6.Z~`!Q14p > 1s3CO7)f F1 4FnUeFϵ`μn=#; mk²jZI֨+ u-9aK.Efmbfzmra1Qλ7 s^qt{h.Lfk (T"wir"$Fpc>*(.=DإA Nn!/zU֕!R3Pi ~zW? a^R LS'eT(ڂ0Rt+A}<ʪѪݬ+)<"l:><~S"`f}䵙mK#&`yWW1~{4 viGZvIv:E 2hE%'8"=݁tB:Z-c|/8l'VNZ jpN.b*29fhI)7J 963m mDc~@:DH~؎#r :uFڿr>\~ |>Q[QzSVNB rCݦ2뾤ؕYVNhz,5"Kz ͇q AV&HC`_ԇHn 'Ijݬa>O2/ݨ#"=\Q+Iq7 (eؕ7}!Sςo!a!3_,.E9Ykw8pcG=}CRt->fG^~箼`Ʒ(B#N #?_.qf#9Z?zFӉ?!.c[םKwg 9;p}h:1w"ӂc jV||298f\UvH2=FK܍h_rZ.*qx qendstream endobj 18 0 obj 2597 endobj 21 0 obj <> stream xYr}WLUw8OZՖWrD*) 8 4a3)].(}ǟnlvgB=aWe?-.Bb> [lτ#O3͓%&FJ3G8XA |6)V5-)xk*7F&[ 4'S#h$ʚw1]gH_o.^dzZl$lVl}I,X?Ul,-:kuxuȊgV7rWPvGl|36qvT(jJ%h5l%w\yYm'0jid?&ϒłAثJb$MX+/Mۃ&6H5*EZnwka4+VY%&#I.wdz&"B[bo陭wud?X{2.9=S8u+c}7*iµ6N@ce$MF6qk `+M ,R>JeE^/G9M#@#H.UGI2wZ;mnZ;GفySVRk AIFaw/,sr{$,Y))j@77s&sOAI(h&͝‹TAS񴪍L"W [fv_!`cd︱v!x$q)1({QYK/ydh+C!euqu9CYc}fP FK+:GcȊVpUEٰdu{3FU` O۲}ޣ_lhP]T++D4 @Nc, E9CsV2jVH ^J&ǂ!k1 0W2,&oqKƍ.;DڀѐhSnZVm(]=*LHFct_7%H dRSSefK">ŔkG wS'(]\1GϑT6Cѵd(GU=UIφcG*#aU߃#"cZHsz5ɭQ.}rpH8;?{i;|3*nk !ٸ̠h+ VO>2Mt4O)1E7)HIn"!'3V"vߠUv`M]i~)189ج2J,}hT|]ӥd? cIl2;}vZk CeKCfCNL}dślt_G}ѬOEvؔ5]6Ɏ*<6{EL|ВiH:=fOddJWO~ Ho}N6kB䜖)λ鮢 9{F=~ێu i?d&iC ul][@rtFVmPeM(,%ә&e;R Mhn@%il9ql ŠRGHWeԭl.?Ǔ&LM2,ir4t⍠[pTdߑA I ߗj_oR<R_Ky$1P%`DrJZ$Evw4QjhߺV p=?0HjŸB[#]폆MҺV⎌ClC ZձmH"-xSM.=0L?MUcӖtqi"mYHuHT5 leT!C'M(x9?F7Ÿ25x-۩WM+NnGPo7oKY1?vv ΋>װ~i06ΠM>\\~pyY=_,..INfQW'N㥁.FV!N@頛%s~UYo1@/T }Vo[9K1ZZ_"~{M/!=gZ[NKfxE!{pJT'"KTc5,ȱ#+G~RWXE/;Æu$1QGcnh2CtwFMS6DOP;m-0y."^BGg¿ 6endstream endobj 22 0 obj 2741 endobj 4 0 obj <> /Contents 5 0 R >> endobj 12 0 obj <> /Contents 13 0 R >> endobj 16 0 obj <> /Contents 17 0 R >> endobj 20 0 obj <> /Contents 21 0 R >> endobj 3 0 obj << /Type /Pages /Kids [ 4 0 R 12 0 R 16 0 R 20 0 R ] /Count 4 >> endobj 1 0 obj <> endobj 11 0 obj <> endobj 15 0 obj <> endobj 19 0 obj <> endobj 23 0 obj <> endobj 8 0 obj <> endobj 24 0 obj <> endobj 7 0 obj <> endobj 25 0 obj <> endobj 10 0 obj <> endobj 9 0 obj <> endobj 26 0 obj <> endobj 2 0 obj <>endobj xref 0 27 0000000000 65535 f 0000011666 00000 n 0000012447 00000 n 0000011586 00000 n 0000011012 00000 n 0000000015 00000 n 0000002684 00000 n 0000012097 00000 n 0000011950 00000 n 0000012308 00000 n 0000012245 00000 n 0000011714 00000 n 0000011154 00000 n 0000002704 00000 n 0000005467 00000 n 0000011773 00000 n 0000011298 00000 n 0000005488 00000 n 0000008157 00000 n 0000011832 00000 n 0000011442 00000 n 0000008178 00000 n 0000010991 00000 n 0000011891 00000 n 0000012031 00000 n 0000012179 00000 n 0000012391 00000 n trailer << /Size 27 /Root 1 0 R /Info 2 0 R /ID [<26FA8B7638754FF3294B885AAE886874><26FA8B7638754FF3294B885AAE886874>] >> startxref 12601 %%EOF optipng-0.7.7/doc/optipng.man.txt000066400000000000000000000312511343170417500167540ustar00rootroot00000000000000OPTIPNG(1) General Commands Manual OPTIPNG(1) NAME OptiPNG - Optimize Portable Network Graphics files SYNOPSIS optipng [-? | -h | -help] optipng [options...] files... DESCRIPTION The OptiPNG program shall attempt to optimize PNG files, i.e. reduce their size to a minimum, without losing semantic information. In addi- tion, this program shall perform a suite of auxiliary functions like integrity checks, metadata recovery and pixmap-to-PNG conversion. The optimization attempts are not guaranteed to succeed. Valid PNG files that cannot be optimized by this program are normally left intact; their size will not grow. The user may request to override this default behavior. FILES The input files are raster image files encoded either in PNG format (the native format), or in an external format. The currently supported external formats are GIF, BMP, PNM and TIFF. OptiPNG processes each image file given in the command line as follows: - If the image is in PNG format: Attempts to optimize the given file in-place. If optimization is successful, or if the option -force is enabled, replaces the original file with its optimized version. The original file is backed up if the option -keep is enabled. - If the image is in an external format: Creates an optimized PNG version of the given file. The output file name is composed from the original file name and the .png extension. Existing files are not overwritten, unless the option -clobber is enabled. OPTIONS General options -?, -h, -help Show a complete summary of options. -backup, -keep Keep a backup of the modified files. -clobber Overwrite the existing output and backup files. Under this option, if the option -backup is not enabled, the old backups of the overwritten files are deleted. -dir directory Write the output files to directory. -fix Enable error recovery. This option has no effect on valid input files. The program will spend a reasonable amount of effort to recover as much data as possible, without increasing the output file size, but the success cannot be generally guaranteed. The pro- gram may even increase the file size, e.g., by reconstructing missing critical data. Under this option, integrity shall take precedence over file size. When this option is not used, the invalid input files are left unprocessed. -force Enforce writing of a new output file. This option overrides the program's decision not to write such file, e.g. when the PNG input is digitally signed (using dSIG), or when the PNG output becomes larger than the PNG input. -log file Log messages to file. For safety reasons, file must have the extension .log. This option is deprecated and will be removed eventually. Use shell redirection. -out file Write output file to file. The command line must contain exactly one input file. -preserve Preserve file attributes (time stamps, file access rights, etc.) where applicable. -quiet, -silent Run in quiet mode. The messages are still written to the log file if the option -log is enabled. -simulate Run in simulation mode: perform the trials, but do not create output files. -v Enable the options -verbose and -version. -verbose Run in verbose mode. -version Show copyright, version and build info. -- Stop option switch parsing. PNG encoding and optimization options -o level Select the optimization level. The optimization level 0 enables a set of optimization opera- tions that require minimal effort. There will be no changes to image attributes like bit depth or color type, and no recompres- sion of existing IDAT datastreams. The optimization level 1 enables a single IDAT compression trial. The trial chosen is what OptiPNG thinks it's probably the most effective. The optimization levels 2 and higher enable multiple IDAT com- pression trials; the higher the level, the more trials. The behavior and the default value of this option may change across different program versions. Use the option -h to see the details pertaining to your specific version. -f filters Select the PNG delta filters. The filters argument is specified as a rangeset (e.g. -f0-5), and the default filters value depends on the optimization level set by the option -o. The filter values 0, 1, 2, 3 and 4 indicate static filtering, and correspond to the standard PNG filter codes (None, Left, Up, Average and Paeth, respectively). The filter value 5 indicates adaptive filtering, whose effect is defined by the libpng(3) library used by OptiPNG. -full Produce a full report on IDAT. This option might slow down the trials. -i type Select the interlace type (0-1). If the interlace type 0 is selected, the output image shall be non-interlaced (i.e. progressive-scanned). If the interlace type 1 is selected, the output image shall be interlaced using the Adam7 method. By default, the output shall have the same interlace type as the input. -nb Do not apply bit depth reduction. -nc Do not apply color type reduction. -np Do not apply palette reduction. -nx Do not apply any lossless image reduction: enable the options -nb, -nc and -np. -nz Do not recode IDAT datastreams. The IDAT optimization operations that do not require recoding (e.g. IDAT chunk concatenation) are still performed. This option has effect on PNG input files only. -zc levels Select the zlib compression levels used in IDAT compression. The levels argument is specified as a rangeset (e.g. -zc6-9), and the default levels value depends on the optimization level set by the option -o. The effect of this option is defined by the zlib(3) library used by OptiPNG. -zm levels Select the zlib memory levels used in IDAT compression. The levels argument is specified as a rangeset (e.g. -zm8-9), and the default levels value depends on the optimization level set by the option -o. The effect of this option is defined by the zlib(3) library used by OptiPNG. -zs strategies Select the zlib compression strategies used in IDAT compression. The strategies argument is specified as a rangeset (e.g. -zs0-3), and the default strategies value depends on the opti- mization level set by the option -o. The effect of this option is defined by the zlib(3) library used by OptiPNG. -zw size Select the zlib window size (32k,16k,8k,4k,2k,1k,512,256) used in IDAT compression. The size argument can be specified either in bytes (e.g. 16384) or kilobytes (e.g. 16k). The default size value is set to the lowest window size that yields an IDAT output as big as if yielded by the value 32768. The effect of this option is defined by the zlib(3) library used by OptiPNG. Editing options -snip Cut one image out of multi-image, animation or video files. Depending on the input format, this may be either the first or the most relevant (e.g. the largest) image. -strip objects Strip metadata objects from a PNG file. PNG metadata is the information stored in any ancillary chunk except tRNS. (tRNS represents the alpha channel, which, even if ignored in rendering, is still a proper image channel in the RGBA color space.) The only option currently supported is -strip all. Notes Options may come in any order (except for --), before, after, or alter- nating with file names. Option names are case-insensitive and may be abbreviated to their shortest unique prefix. Some options may have arguments that follow the option name, separated by whitespace or the equal sign ('='). If the option argument is a num- ber or a rangeset, the separator may be omitted. For example: -out newfile.png <=> -out=newfile.png -o3 <=> -o 3 <=> -o=3 -f0,3-5 <=> -f 0,3-5 <=> -f=0,3-5 Rangeset arguments are cumulative; e.g. -f0 -f3-5 <=> -f0,3-5 -zs0 -zs1 -zs2-3 <=> -zs0,1,2,3 <=> -zs0-3 EXTENDED DESCRIPTION The PNG optimization algorithm consists of the following steps: 1. Reduce the bit depth, the color type and the color palette of the image. This step may reduce the size of the uncompressed image, which, indirectly, may reduce the size of the compressed image (i.e. the size of the output PNG file). 2. Run a suite of compression methods and strategies and select the compression parameters that yield the smallest output file. 3. Store all IDAT contents into a single chunk, eliminating the over- head incurred by repeated IDAT headers and CRCs. 4. Set the zlib window size inside IDAT to a mininum that does not affect the compression ratio, reducing the memory requirements of PNG decoders. Not all of the above steps need to be executed. The behavior depends on the actual input files and user options. Step 1 may be customized via the no-reduce options -nb, -nc, -np and -nx. Step 2 may be customized via the -o option, and may be fine-tuned via the options -zc, -zm, -zs and -zw. Step 3 is always executed. Step 4 is executed only if a new IDAT is being created, and may be fine- tuned via the option -zw. Extremely exhaustive searches are not generally expected to yield sig- nificant improvements in compression ratio, and are recommended to advanced users only. EXAMPLES optipng file.png # default speed optipng -o5 file.png # slow optipng -o7 file.png # very slow BUGS Lossless image reductions are not completely implemented. (This does not affect the integrity of the output files.) Here are the missing pieces: - The color palette reductions are implemented only partially. - The bit depth reductions below 8, for grayscale images, are not implemented yet. Encoding of images whose total IDAT size exceeds 2GB is not supported. TIFF support is limited to uncompressed, PNG-compatible (grayscale, RGB and RGBA) images. Metadata is not imported from the external image formats. There is no support for pipes, streams, extended file attributes or access control lists. SEE ALSO png(5), libpng(3), zlib(3), pngcrush(1), pngrewrite(1). STANDARDS The files produced by OptiPNG are compliant with PNG-2003: Glenn Randers-Pehrson et al. Portable Network Graphics (PNG) Specifi- cation, Second Edition. W3C Recommendation 10 November 2003; ISO/IEC IS 15948:2003 (E). http://www.w3.org/TR/PNG/ AUTHOR OptiPNG is written and maintained by Cosmin Truta. This manual page was originally written by Nelson A. de Oliveira for the Debian Project. It was later updated by Cosmin Truta, and is now part of the OptiPNG distribution. OptiPNG version 0.7.7 2017-Dec-27 OPTIPNG(1) optipng-0.7.7/doc/png_optimization.html000066400000000000000000000616351343170417500202520ustar00rootroot00000000000000 A guide to PNG optimization

A guide to PNG optimization

1. Background

1.1 The PNG file format

The Portable Network Graphics (PNG) is a format for storing compressed raster graphics. The compression engine is based on the Deflate method [RFC1951], designed by PKWare and originally used in PKZIP.

The PNG format is defined by the PNG Specification. This specification was developed by an ad-hoc group named the PNG Development Group, and it is both an International Standard (published under the formal name ISO/IEC 15948) and a W3C Recommendation.

PNG was initially intended as a superior, patent-free replacement of GIF. The final outcome is a modern, extensible, reliable image format, capable to handle an impressive number of image types (from 1-bit black-and-white images up to 48-bit RGB images with a full 16-bit alpha channel), and geared by a significantly stronger lossless compression engine (typically 5-25% better than GIF).

Unlike other lossless compression schemes, PNG compression does not depend solely on the statistics of the input, but it may vary within wide limits, depending on the compressor's implementation. A good PNG encoder must be able to take informed decisions about the factors that affect the size of the output. The purpose of this article is to provide information about these factors, and to give advice on implementing efficient PNG encoders.

1.2 The PNG compression

The PNG compression works in a pipeline manner.

In the first stage, the image pixels are passed through a lossless arithmetic transformation named delta filtering, or simply filtering, and sent further as a (filtered) byte sequence. Filtering does not compress or otherwise reduce the size of the data, but it makes the data more compressible.

In the second stage, the filtered byte sequence is passed through the Ziv-Lempel algorithm (LZ77), producing LZ77 codes that are further compressed by the Huffman algorithm in the third and final stage. The combination of the last two stages is referred to as the Deflate compression, a widely-used, patent-free algorithm for universal, lossless data compression. The maximum size of the LZ77 sliding window in Deflate is 32768 bytes, and the LZ77 matches can be between 3 and 258 bytes long.

A complete description of the PNG compression is beyond the scope of this guide. The PNG Specification describes the format completely, and provides a complete list of references to the underlying technologies.

2. Factors that affect the PNG file size

Like any other compression scheme, PNG compression depends on the statistics of the input data. In addition, it depends on the following PNG-specific parameters:
  1. The PNG image type
  2. The PNG delta filters
  3. The strategy of searching LZ77 matches
  4. The size of the Huffman buffers inside the Deflate encoder

Depending on how these parameters are chosen by the implementation, PNG compression may vary within wide limits. The process of selecting the best configuration is computationally infeasible, but heuristics to select a satisfactory configuration are available. The problem of improving these heuristics constitutes an interesting subject for research.

2.1 The PNG image type

The type of a PNG image is defined in the IHDR image header. The image has a certain bit depth, up to 16 bits per sample, and a certain color type, from Grayscale to RGB+Alpha. If two PNG files of different types represent exactly the same image, each file can be regarded as a lossless transformation of the other. A lossless transformation can reduce the uncompressed stream, and such a transformation is named image reduction. In most cases, image reductions are capable of reducing the compressed stream (which is, in fact, our interest), as an indirect effect of reducing the size of the compressor's input.

The possible image reductions are:
  • Bit depth reduction
    The bit depth can be reduced to a minimum value that is acceptable for all samples. For example, if all sample values in a 16-bit image have the form (256+1)*n, (e.g. #0000, #2323, #FFFF), then the bit depth can be reduced to 8, and the new sample values will become n, (e.g. #00, #23, #FF).
  • Color type reduction
    - If an RGB image has 256 distinct colors or less, it can be reencoded as a Palette image.
    - If an RGB or Palette image has only gray pixels, it can be reencoded as Grayscale.
    A color type reduction can also enable a bit depth reduction.
  • Color palette reduction
    If the color palette contains redundant entries (i.e. duplicate entries that indicate the same RGB value) or sterile entries (i.e. entries that do not have a correspondent in the raw pixel data), these entries can be removed.
    A color palette reduction can also enable a bit depth reduction.
  • Alpha channel reduction
    If all pixels in a Grayscale+Alpha or an RGB+Alpha image are fully opaque (i.e. all alpha components are equal to 2^bitdepth-1), or if the transparency information can be stored entirely in a (much cheaper) tRNS chunk, the alpha channel can be stripped.

There are, however, a few cases when some image type reductions do not necessarily lead to the reduction of the compressed stream. The PNG-Tech site contains experimental analyses of these possibilities; for example, see the article 8 bits per pixel in paletted images.

Interlacing, useful for a faster, progressive rendering, is another component of the PNG image type that affects compression. In an interlaced stream, the samples corresponding to neighboring pixels are stored far away, hence the data in it is less correlated and less compressible. Unlike JPEG, where interlacing may improve the compression slightly, the PNG interlacing degrades the compression significantly.

2.2 The PNG delta filters

The role of filtering can be illustrated in the following example. Assume the sequence 2, 3, 4, 5, 6, 7, 8, 9. Although it has much redundancy, the sequence is not compressible by a Ziv-Lempel compressor, nor by a Huffman compressor. However, if one makes a simple and reversible transformation, replacing each value with the numerical difference between it and the value to its left, the sequence becomes 2, 1, 1, 1, 1, 1, 1, 1, which is highly compressible.

The PNG format employs five types of filters: None, Left, Up, Average, and Paeth. The first filter leaves the original data intact, and the other four are subtracting from each pixel a value that involves the neighbor pixels from the left, up, and/or the upper left.

A certain filter is assigned to each row, and is applied to all pixels from that row. Therefore, an image can be delta-filtered in a huge number of possible configurations (5 ^ height), and each configuration leads to a different compressed output. Two different filter configurations may make a difference in the compressed file size by a couple of factors, so a careful choice of filters is of paramount importance.

It is possible to apply a single filter to all rows, or to apply different filters to different rows. In the former case, the filtering process is fixed; in the latter, it is adaptive.

While an exhaustive search is unfeasible, the PNG Specification suggests a heuristic filtering strategy:
  • If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e. use fixed filtering, with the filter None).
  • (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is not smaller than 8, then use adaptive filtering as follows: independently for each row, apply all five filters and select the filter that produces the smallest sum of absolute values per row.

Cases where the above heuristics are less than optimal are shown on the PNG-Tech site; for example, see Brute-force vs. heuristic filtering.

2.3 The strategy of searching LZ77 matches

The Ziv-Lempel algorithm works under the assumption that contiguous sequences appear repeatedly in the input stream. If the sequence to be encoded matches one or more sequences already present in the sliding history window, the encoder sends a LZ77 pair (distance, length) that points to the closest match. In most LZ77 incarnations, including Deflate, smaller distance codes are encoded more concisely.

In Deflate, in particular, the regular (non-matched) symbols, and the match lengths, are sent to the same Huffman coder, while the match distances are sent to a separate Huffman coder. If the LZ77 matches fall between the accepted boundaries (i.e. they are not shorter than 3 and not longer than 258), a greedy strategy will accept them as a replacement for the symbols to which they correspond.

The greedy strategy is preferable when compressing text files, or many types of binary files, but it may be suboptimal when compressing filtered data, such as the byte strings that come from a PNG filter. Filtered data consist mostly of small values with a pseudo-random distribution. Therefore, in certain situations, it may be desirable to favor the encoding of individual symbols, even if matches that may replace these symbols exist.

The zlib Reference Library is a reference implementation of Deflate, which is further used by the PNG Reference Library. By default, zlib selects the greedy strategy, but the user is able to specify his or her custom preference via the strategy parameter. This parameter can take one of the following values:
- Z_DEFAULT_STRATEGY = 0, the default greedy search strategy.
- Z_FILTERED = 1, a strategy in which the matches are accepted only if their length is 6 or bigger.
- Z_HUFFMAN_ONLY = 2, a fast strategy in which the Ziv-Lempel algorithm is entirely bypassed, and all the symbols from the input are encoded directly by the Huffman coder.
- Z_RLE = 3 (appeared in the zlib-1.2.x series), a fast strategy in which the LZ77 algorithm is essentially reduced to the Run-Length Encoding algorithm. In other words, the matches are accepted only if their distance is 1. For example, the 10-symbol sequence "aaaaaaaaaa" can be LZ77-encoded as ['a', (distance=1, length=9)]; by removing distance=1 from the picture, this encoding can be regarded as a peculiar run-length encoding (which differs from the classic RLE by using length=9 instead of count=10).
The strategy parameter affects only the compression ratio. It does not affect the correctness of the compressed output, even if it is set to an inappropriate value.

It was experimentally observed that the LZ77 search is occasionally capable of producing smaller PNGs if it is less exhaustive. The reason behind this act resides in the same category of "strategic searches" discussed here. Unfortunately, there is no known method of anticipating which search level (from the fastest and the least exhaustive, to the slowest and the most exhaustive) is better, other than assuming "the most exhaustive is better in most cases".

Unfortunately, even a "filtered" strategy does not always produce better results than a "greedy" strategy on filtered input, and the only known method to obtain the best combination is by multiple trials. Experiments and measurements can, again, be found on the PNG-Tech site; for example, see the original Z_RLE strategy proposal.

2.4 The size of Huffman buffers

As mentioned earlier, the entropy encoder inside the Deflate method is the static Huffman algorithm. The output of LZ77 is fed into a buffer which is occasionally flushed by sending a static Huffman tree followed by all the Huffman codes, to the output of Deflate. After this, both the buffer and the Huffman tree are reset, waiting for the subsequent LZ77 codes to come and refill the buffer.

The Deflate specification refers to dynamic Huffman codes. However, this is a misnomer, in which the term dynamic is used in contrast to the fixed Huffman codes. The fixed Huffman codes are simply built according to a predefined Huffman tree, without regard to the actual symbol frequencies. The dynamic Huffman codes referred to by the Deflate specification are NOT built by the dynamic Huffman algorithm, as defined, for example, by Faller, Gallager and Knuth (the FGK algorithm), or by Vitter (the V algorithm). The predefined Huffman tree was introduced in PKZIP as a fast compression alternative, but it produces poor results even on text, and it is almost useless in PNG compression. Still, a PNG stream that contains codes built by the fixed (predefined) Huffman tree, is a valid stream, and a compliant PNG reader must decode this stream correctly.

It is desirable to establish the buffer boundaries so that sequences conforming to the same probability model are fit in the same Huffman buffer. Methods for approaching these boundaries exist, but they are not used in the mainstream Deflate implementation(s). Instead, the buffers are flushed when a limit (typically, 16k LZ77 codes) is reached. This is, however, a fast approach, and the results are satisfactory.

The size of Huffman buffers is indirectly determined by the encoder's memory (usage) level. For this reason, certain memory levels might be good for certain types of images.

3. PNG (lossless) optimization programs

The multitude of PNG encoding programs is listed at http://www.libpng.org/pub/png/pngapps.html. Their performance varies as much as the range of possible compression ratios; the good encoders are at least applying the filtering heuristics, described briefly in the PNG Specification, and illustrated above.
Some programs gain extra compression by discarding some of the data in the input images (so these programs are lossy!)

This section contains the small list of PNG optimization programs that show a particular concern towards obtaining a file size as small as possible. They work by performing repeated compression trials, applying various parameter sets, and selecting the parameter set that yields the smallest compressed output.

  • pngrewrite by Jason Summers, available at http://www.pobox.com/~jason1/pngrewrite, is an open-source program that performs lossless image reductions. It works best in conjunction with pngcrush (see below); the user should run pngcrush after pngrewrite.

  • pngcrush by Glenn Randers-Pehrson, available at http://pmt.sourceforge.net/pngcrush, is an open-source program that iterates over PNG filters and zlib (Deflate) parameters, compresses the image repeatedly using each parameter configuration, and chooses the configuration that yields the smallest compressed (IDAT) output. At the user's option, the program can explore few (below 10) or many (a brute-force traversal over more than 100) configurations. The method of selecting the parameters for "few" trials is particularly effective, and the use of a brute-force traversal is generally not recommended.

    In addition, pngcrush offers a multitude of extra features, such as recovery of erroneous PNG files (e.g. files containing bad CRCs), and chunk-level editing of PNG meta-data.

  • OptiPNG by Cosmin Truţa, available at http://www.cs.toronto.edu/pngtech/optipng, is a newer open-source program, inspired from pngcrush, but designed to be more flexible and to run faster. Unlike pngcrush, OptiPNG performs the trials entirely in memory, and writes only the final output file on the disk. Moreover, it offers multiple optimization presets to the user, who can choose among a range of options from "very few trials" to "very many trials" (in contrast to the coarser "smart vs. brute" option offered by pngcrush).

    It is important to mention that the achieved compression ratio is less and less likely to improve when higher-level presets (trigerring more trials) are being used. Even if the program is capable of searching automatically over more than 200 configurations (and the advanced users have access to more than 1000 configurations!), a preset that selects around 10 trials should be satisfactory for most users. Furthermore, a preset that selects between 30-40 trials should be satisfactory for all users, for it is very, very unlikely to be beaten significantly by any wider search. The rest of the trial configurations are offered rather as a curiosity (but they were used in the experimentation from which we concluded they are indeed useless!)

  • AdvanceCOMP by Andrea Mazzoleni is a set of tools for optimizing ZIP/GZIP, PNG and MNG files, based on the powerful 7-Zip deflation engine. The name of the PNG optimization tool is AdvPNG. At the time of this writing, AdvPNG does not perform image reductions, so the use of pngrewrite or OptiPNG prior to optimiziation may be necessary. However, given the effectivenes of 7-Zip deflation, AdvanceCOMP is a powerful contender.

    The AdvanceCOMP tool set is a part of the AdvanceMAME project, available at http://advancemame.sourceforge.net.

  • PNGOut by Ken Silverman, available at http://advsys.net/ken/utils.htm, is a freely-available compiled program (no source code), running on Windows and Linux. According to our tests, the compression ratio achieved by PNGOut is comparable to that of AdvPNG. Unfortunately, due to the lack of information, we cannot say much about this tool.

    A nice GUI frontend for PNGOut, named PNGGauntlet, is available at http://www.numbera.com/software/pnggauntlet.aspx.

4. An extra note on losslessness

What is lossless PNG optimization, after all? This is a straightforward question, whose answer is intuitive, yet not so straightforward.

Losslessness in the strictest sense, where no information whatsoever is lost, can only be achieved by leaving the original file (any file) intact, or by transforming it (e.g. compressing it, encrypting it) in such a way that there is an inverse transformation which recovers it completely, bit by bit.

In the case of PNG images, this condition of strict losslessness has little relevance to the casual graphics user, and is, therefore, too strong. There are instances where strict losslessness is required; for example, when handling certified PNG files whose integrity is guaranteed by an external checksum like MD5 or SHA, or by a digital signature such as dSIG. Most of the time, however, it is desirable to relax the notion of PNG losslessness, to the extent of not losing any information that pertains to the rendered image and to the semantic value of the metadata that accompanies the image. This allows the user to concentrate on what is really important when it comes to preserving the contents of a PNG image, and enables the concept of PNG optimization tools.

A lossless transform of a PNG image file is a transform which fully preserves the rendered RGB triples (the RGB triples that come either directly, or from a palette index, or from a gray->RGB expansion), the rendered transparency (the alpha samples that come either directly, or from a tRNS chunk, or the implicit 100% opacity assumed due to the lack of any explicit transparency information), the order of rendering (sequential or interlaced), and the semantics contained by the ancillary chunks.
This definition allows the execution of the above-mentioned image reduction operations, and the recompression of IDAT. It also allows the alteration or the elimination of other pieces of information that are technically valid, but have no influence on any presentation of the image pixels:
  • The information that pertains to Deflate streams, either inside IDAT, or in other compressed chunks like zTXt, iTXt or iCCP; e.g. the LZ77 window size, the type and size of Deflate blocks, etc. (The only thing that matters is that the decompressed byte sequence must remain the same.)
  • The order of palette entries inside a PLTE chunk. (When changing this order, the information that depends on it, such as the palette-encoded pixels or the tRNS information, must be updated accordingly.)
  • RGB triples that do not correspond to any pixel in the actual image, but are stored in a tRNS chunk.
  • Fully opaque tRNS entries in a palette image.
  • Gamma correction (gAMA) or significant bit (sBIT) information inside an image that consists exclusively of samples whose intensity is either minimum (0) or maximum (2^bitdepth-1).
  • The fact that a textual comment is stored uncompressed in a tEXt chunk, or compressed in a zTXt chunk, or with no translation in an iTXt chunk.
  • Etcetera.

If any of the discardable information is important in a particular application, and lossless PNG optimization is still desirable, it is recommended to store this information in ancillary chunks, rather than hack it inside critical chunks. For example, if sterile palette entries are necessary (e.g. for later editing stages), it is recommended to store them inside a suggested palette (sPLT) chunk, rather than keeping them inside PLTE.

5. Selective bibliography

Besides the discussed specifications, the references below provide essential information necessary to comprehend the contents of this article.

  • Thomas Boutell, Glenn Randers-Pehrson et al. Portable Network Graphics (PNG) Specification, Second Edition. ISO/IEC 15948:2003(E); W3C Recommendation 10 November 2003.
  • David A. Huffman. A method for the construction of minimum redundancy codes. In Proceedings of the Institute of Radio Engineers, vol. 40, no. 9, pp. 1098-1101, September 1952.
  • Jacob Ziv and Abraham Lempel. A universal algorithm for data compression. IEEE Transactions on Information Theory, vol. IT-23, no. 3, pp. 337-343, May 1977.
    Due to a historical accident, the famous algorithm is better-known as the "Lempel-Ziv (LZ) algorithm", even though the "Ziv-Lempel algorithm" is a more legitimate name.
  • Greg Roelofs. PNG: The definitive guide. O'Reilly and Associates, 1999.

Copyright © 2003-2008 Cosmin Truţa. Permission to distribute freely.
Appeared: 7 Apr 2003.
Last updated: 10 May 2008.
optipng-0.7.7/doc/todo.txt000066400000000000000000000026651343170417500154760ustar00rootroot00000000000000OptiPNG - TO-DO list ==================== - Compression improvements: Use zlib's deflateTune(). Use 7zip's and/or zopfli's powerful deflation engine. - Speed improvements: Avoid repeated filtering when trying a filter value more than once. - Text chunk optimization: Smart selection between tEXt and zTXt. Smart selection between uncompressed iTXt and compressed iTXt. - Improved support for reading external image formats (e.g. compressed TIFF). - More file recovery features. - Input from stdin; output to stdout: cat infile | optipng > outfile optipng -stdout infile > outfile - Optimization of an entire directory, with and without subdirectory recursion: optipng dir/ optipng -recursive dir/ - Support for conversion to a desired bit depth and color type: optipng -b16 -c6 files ... - Support for handling metadata, e.g.: optipng -set tEXt=, # add or update chunk optipng -set sRGB=0 # add or update chunk optipng -set image.precision= # set the precision of all samples optipng -set image.alpha.precision= # set the precision of alpha samples optipng -reset image.alpha # make the image fully opaque optipng -strip hIST,sPLT # strip hIST and sPLT optipng -strip all -protect iCCP # strip all metadata except iCCP - Parallelization on multi-processor/multi-core machines: optipng -jobs 4 files ... optipng-0.7.7/src/000077500000000000000000000000001343170417500140015ustar00rootroot00000000000000optipng-0.7.7/src/Makefile.in000066400000000000000000000005531343170417500160510ustar00rootroot00000000000000all: cd optipng && \ $(MAKE) && \ cd .. test: cd optipng && \ $(MAKE) test && \ cd .. check: test install: cd optipng && \ $(MAKE) install && \ cd .. uninstall: cd optipng && \ $(MAKE) uninstall && \ cd .. clean: cd optipng && \ $(MAKE) clean && \ cd .. distclean: cd optipng && \ $(MAKE) distclean && \ cd .. -rm -f ../Makefile Makefile optipng-0.7.7/src/cexcept/000077500000000000000000000000001343170417500154345ustar00rootroot00000000000000optipng-0.7.7/src/cexcept/README000066400000000000000000000161151343170417500163200ustar00rootroot00000000000000cexcept: README 2.0.1-optipng (2011-Jul-22) Updated by Cosmin Truta http://www.nicemice.net/cexcept/ Adam M. Costello http://www.nicemice.net/amc/ cexcept (pronounced "see except" in English) is a package providing a Try/Catch/Throw exception handling interface for ANSI C (C89 and subsequent ISO standards). It does not attempt to handle system exceptions like floating-point exceptions or addressing exceptions, nor compiler-generated exceptions like C++ exceptions; it is intended as an enhanced user-friendly alternative to setjmp() and longjmp(). The package consists of the following files: name version ---------- ------- README 2.0.1-optipng cexcept.h 2.0.1-optipng example1.c 2.0.0 example2.c 2.0.0 rationale 2.0.0 The package is both free-as-in-speech and free-as-in-beer: Copyright (c) 2000-2008 Adam M. Costello and Cosmin Truta. This package may be modified only if its author and version information is updated accurately, and may be redistributed only if accompanied by this unaltered notice. Subject to those restrictions, permission is granted to anyone to do anything with this package. The copyright holders make no guarantees regarding this package, and are not responsible for any damage resulting from its use. The version number of this README file can be considered the version number of the whole package. The file cexcept.h contains the documentation and implementation of the interface. The other files are supporting documents. The project web page is: http://www.nicemice.net/cexcept/ Here is another place to obtain the package, not guaranteed to always have the very latest version, but probably more highly available: http://cexcept.sourceforge.net/ The remainder of this file is a log of changes. 2011-Jul-22-Fri cexcept.h 2.0.1 --> 2.0.1-optipng * Made exception__prev volatile to avoid "variable might be clobbered by longjmp" warnings when a function contains multiple Try blocks. 2008-Jul-23-Wed cexcept.h 2.0.0 --> 2.0.1 * Clarified the license. * Reworded the introductory comments. * Bug fix: The statement following Try could not be an if-statement (without else); the Catch would then be parsed wrong. * Quieted a new warning in gcc 4.2. README 2.0.0 --> 2.0.1 * Reworded the license to agree with cexcept.h. * Updated the URLs. 2001-Jul-12-Thu cexcept.h 1.0.0 --> 2.0.0 * The documentation had neglected to mention that the Catch expression was evaluated before the Try clause was executed. Rather than document this unintuitive behavior, we have changed the interface so that the Catch expression is not evaluated unless and until an exception is caught. This change will not affect applications that never used Catch expressions with side effects. * The implementation had been technically incorrect because it modified the object named by the Catch expression between the setjmp and longjmp calls, even though it might be a non-volatile automatic object (which it was in example.c). The problem (which affected no known compilers) has been corrected by performing two copies: first into volatile temporary storage before the longjmp, then into the Catch expression after the longjmp. * The requirement that the Catch expression have the "exact same type" that was passed to define_exception_type() has been slightly relaxed to disregard type qualifiers. * In the license, "no guarantees about the correctness of this file" has been changed to "no guarantees regarding this file". * Notes have been added that "real" exceptions are not supported, and the size of the exception type has performance implications. rationale 1.0.0 --> 2.0.0 * Removed the obsolete question about why the Catch expression is always evaluated. * Updated the answer to the question about the type of the Catch expression, to correspond to the new implementation. * Added a question about why two copies are necessary. * Added a question about why "real" exceptions cannot be caught. example.c 1.0.0 --> example1.c 2.0.0 example2.c 1.0.0 --> 2.0.0 * Renamed example.c to example1.c. * Changed the version number to agree with cexcept.h in the first two places (2.0.*). README 1.0.0 --> 2.0.0 * Reworded the license to agree with cexcept.h. * Changed the version number to agree with cexcept.h in the first two places (2.0.*). 2000-Jun-21-Wed cexcept.h 0.6.1 --> 1.0.0 * Changed the version number to indicate stability. * Changed "an lvalue" to "a modifiable lvalue" to agree with the language in the ISO C Standard. * Added hints about dealing with the inability to return from a Try clause, and with automatic variables modified within a Try clause. * Clarified the restriction on Throw'ing a comma-expression. example.c 0.6.0 --> 1.0.0 * Changed the version number to agree with cexcept.h in the first two places (1.0.*). example2.c 0.6.0 --> 1.0.0 * Changed the version number to agree with cexcept.h in the first two places (1.0.*). rationale 0.6.1 --> 1.0.0 * Changed the version number to agree with cexcept.h in the first two places (1.0.*). README 0.6.3 --> 1.0.0 * Changed the version number to agree with cexcept.h in the first two places (1.0.*). 2000-Apr-22-Sat cexcept.h 0.6.0 --> 0.6.1 * Clarified that the wrapper .h file is needed only when there are multiple .c files. 2000-Apr-08-Sat rationale 0.6.0 --> 0.6.1 * Added rationale for disallowing jumping in/out of Try clauses. * Expanded the discussion of finally clauses. * Added rationale for the lack of expressionless Throw. 2000-Apr-07-Fri Created README, which incorporates changelog. cexcept.h amc.0.5.3 --> 0.6.0 * The expression passed to Catch must now have exactly the same type passed to define_exception_type(), and it is always evaluated exactly once, regardless of whether an exception is caught. * Added Catch_anonymous. * Changed init_exception_context() to take an argument, and to be optional for statically allocated contexts. * Clarified allowable exception types, added examples. * Clarified the restrictions on jumping in Try/Catch statements. * Reworded some other parts of the documentation. cexcept-example.c amc.0.5.0 --> example.c 0.6.0 * Now uses the 0.6.* interface, and demonstrates Catch_anonymous. cexcept-example2.c amc.0.5.0 --> example2.c 0.6.0 * Now uses the 0.6.* interface. cexcept-rationale amc.0.5.1 --> rationale 0.6.0 * Added rationale for the new Catch expression semantics. 2000-Apr-01-Fri cexcept.h amc.0.5.2 --> amc.0.5.3 * Eliminated a compiler warning about an uninitialized variable. * Improved the documentation of allowable exception types. * Added advice about using a macro for the_exception_context, and changed the example accordingly. * Improved the documentation regarding jumping out of Try and Catch. Earlier changes were not logged. optipng-0.7.7/src/cexcept/README.optipng.txt000066400000000000000000000005431343170417500206130ustar00rootroot00000000000000Name: cexcept Summary: Exception handling in C Authors: Adam M. Costello and Cosmin Truta Version: 2.0.1-optipng Base version: 2.0.1 URL: http://www.nicemice.net/cexcept/ Changes: - Made exception__prev volatile to avoid "variable might be clobbered by longjmp" warnings when a function contains multiple Try blocks. Patch: cexcept-2-0-1-optipng.diff optipng-0.7.7/src/cexcept/cexcept-2-0-1-optipng.diff000066400000000000000000000033061343170417500220330ustar00rootroot00000000000000diff -ru cexcept-2-0-1/cexcept.h cexcept-2-0-1-optipng/cexcept.h --- cexcept-2-0-1/cexcept.h 2008-07-23 15:35:51.000000000 -0400 +++ cexcept-2-0-1-optipng/cexcept.h 2011-07-22 00:49:00.000000000 -0400 @@ -1,6 +1,9 @@ /*=== -cexcept.h 2.0.1 (2008-Jul-19-Sat) +cexcept.h 2.0.1-optipng (2011-Jul-22) +Derived from cexcept.h 2.0.1 by Cosmin Truta + http://www.nicemice.net/cexcept/ + Adam M. Costello http://www.nicemice.net/amc/ @@ -210,7 +213,8 @@ #define Try \ { \ - jmp_buf *exception__prev, exception__env; \ + jmp_buf * volatile exception__prev; \ + jmp_buf exception__env; \ exception__prev = the_exception_context->penv; \ the_exception_context->penv = &exception__env; \ if (setjmp(exception__env) == 0) { \ diff -ru cexcept-2-0-1/README cexcept-2-0-1-optipng/README --- cexcept-2-0-1/README 2008-07-23 15:35:51.000000000 -0400 +++ cexcept-2-0-1-optipng/README 2011-07-22 00:49:00.000000000 -0400 @@ -1,5 +1,8 @@ -cexcept: README 2.0.1 (2008-Jul-23-Wed) +cexcept: README 2.0.1-optipng (2011-Jul-22) +Updated by Cosmin Truta + http://www.nicemice.net/cexcept/ + Adam M. Costello http://www.nicemice.net/amc/ @@ -14,8 +17,8 @@ name version ---------- ------- - README 2.0.1 - cexcept.h 2.0.1 + README 2.0.1-optipng + cexcept.h 2.0.1-optipng example1.c 2.0.0 example2.c 2.0.0 rationale 2.0.0 @@ -49,6 +52,12 @@ The remainder of this file is a log of changes. +2011-Jul-22-Fri + + cexcept.h 2.0.1 --> 2.0.1-optipng + * Made exception__prev volatile to avoid "variable might be clobbered + by longjmp" warnings when a function contains multiple Try blocks. + 2008-Jul-23-Wed cexcept.h 2.0.0 --> 2.0.1 optipng-0.7.7/src/cexcept/cexcept.h000066400000000000000000000241171343170417500172450ustar00rootroot00000000000000/*=== cexcept.h 2.0.1-optipng (2011-Jul-22) Derived from cexcept.h 2.0.1 by Cosmin Truta http://www.nicemice.net/cexcept/ Adam M. Costello http://www.nicemice.net/amc/ An interface for exception-handling in ANSI C (C89 and subsequent ISO standards), developed jointly with Cosmin Truta. Copyright (c) 2000-2008 Adam M. Costello and Cosmin Truta. This software may be modified only if its author and version information is updated accurately, and may be redistributed only if accompanied by this unaltered notice. Subject to those restrictions, permission is granted to anyone to do anything with this software. The copyright holders make no guarantees regarding this software, and are not responsible for any damage resulting from its use. The cexcept interface is not compatible with and cannot interact with system exceptions (like division by zero or memory segmentation violation), compiler-generated exceptions (like C++ exceptions), or other exception-handling interfaces. When using this interface across multiple .c files, do not include this header file directly. Instead, create a wrapper header file that includes this header file and then invokes the define_exception_type macro (see below). The .c files should then include that header file. The interface consists of one type, one well-known name, and six macros. define_exception_type(type_name); This macro is used like an external declaration. It specifies the type of object that gets copied from the exception thrower to the exception catcher. The type_name can be any type that can be assigned to, that is, a non-constant arithmetic type, struct, union, or pointer. Examples: define_exception_type(int); enum exception { out_of_memory, bad_arguments, disk_full }; define_exception_type(enum exception); struct exception { int code; const char *msg; }; define_exception_type(struct exception); Because throwing an exception causes the object to be copied (not just once, but twice), programmers may wish to consider size when choosing the exception type. struct exception_context; This type may be used after the define_exception_type() macro has been invoked. A struct exception_context must be known to both the thrower and the catcher. It is expected that there be one context for each thread that uses exceptions. It would certainly be dangerous for multiple threads to access the same context. One thread can use multiple contexts, but that is likely to be confusing and not typically useful. The application can allocate this structure in any way it pleases--automatic, static, or dynamic. The application programmer should pretend not to know the structure members, which are subject to change. struct exception_context *the_exception_context; The Try/Catch and Throw statements (described below) implicitly refer to a context, using the name the_exception_context. It is the application's responsibility to make sure that this name yields the address of a mutable (non-constant) struct exception_context wherever those statements are used. Subject to that constraint, the application may declare a variable of this name anywhere it likes (inside a function, in a parameter list, or externally), and may use whatever storage class specifiers (static, extern, etc) or type qualifiers (const, volatile, etc) it likes. Examples: static struct exception_context * const the_exception_context = &foo; { struct exception_context *the_exception_context = bar; ... } int blah(struct exception_context *the_exception_context, ...); extern struct exception_context the_exception_context[1]; The last example illustrates a trick that avoids creating a pointer object separate from the structure object. The name could even be a macro, for example: struct exception_context ec_array[numthreads]; #define the_exception_context (ec_array + thread_id) Be aware that the_exception_context is used several times by the Try/Catch/Throw macros, so it shouldn't be expensive or have side effects. The expansion must be a drop-in replacement for an identifier, so it's safest to put parentheses around it. void init_exception_context(struct exception_context *ec); For context structures allocated statically (by an external definition or using the "static" keyword), the implicit initialization to all zeros is sufficient, but contexts allocated by other means must be initialized using this macro before they are used by a Try/Catch statement. It does no harm to initialize a context more than once (by using this macro on a statically allocated context, or using this macro twice on the same context), but a context must not be re-initialized after it has been used by a Try/Catch statement. Try statement Catch (expression) statement The Try/Catch/Throw macros are capitalized in order to avoid confusion with the C++ keywords, which have subtly different semantics. A Try/Catch statement has a syntax similar to an if/else statement, except that the parenthesized expression goes after the second keyword rather than the first. As with if/else, there are two clauses, each of which may be a simple statement ending with a semicolon or a brace-enclosed compound statement. But whereas the else clause is optional, the Catch clause is required. The expression must be a modifiable lvalue (something capable of being assigned to) of the same type (disregarding type qualifiers) that was passed to define_exception_type(). If a Throw that uses the same exception context as the Try/Catch is executed within the Try clause (typically within a function called by the Try clause), and the exception is not caught by a nested Try/Catch statement, then a copy of the exception will be assigned to the expression, and control will jump to the Catch clause. If no such Throw is executed, then the assignment is not performed, and the Catch clause is not executed. The expression is not evaluated unless and until the exception is caught, which is significant if it has side effects, for example: Try foo(); Catch (p[++i].e) { ... } IMPORTANT: Jumping into or out of a Try clause (for example via return, break, continue, goto, longjmp) is forbidden--the compiler will not complain, but bad things will happen at run-time. Jumping into or out of a Catch clause is okay, and so is jumping around inside a Try clause. In many cases where one is tempted to return from a Try clause, it will suffice to use Throw, and then return from the Catch clause. Another option is to set a flag variable and use goto to jump to the end of the Try clause, then check the flag after the Try/Catch statement. IMPORTANT: The values of any non-volatile automatic variables changed within the Try clause are undefined after an exception is caught. Therefore, variables modified inside the Try block whose values are needed later outside the Try block must either use static storage or be declared with the "volatile" type qualifier. Throw expression; A Throw statement is very much like a return statement, except that the expression is required. Whereas return jumps back to the place where the current function was called, Throw jumps back to the Catch clause of the innermost enclosing Try clause. The expression must be compatible with the type passed to define_exception_type(). The exception must be caught, otherwise the program may crash. Slight limitation: If the expression is a comma-expression, it must be enclosed in parentheses. Try statement Catch_anonymous statement When the value of the exception is not needed, a Try/Catch statement can use Catch_anonymous instead of Catch (expression). Everything below this point is for the benefit of the compiler. The application programmer should pretend not to know any of it, because it is subject to change. ===*/ #ifndef CEXCEPT_H #define CEXCEPT_H #include #define define_exception_type(etype) \ struct exception_context { \ jmp_buf *penv; \ int caught; \ volatile struct { etype etmp; } v; \ } /* etmp must be volatile because the application might use automatic */ /* storage for the_exception_context, and etmp is modified between */ /* the calls to setjmp() and longjmp(). A wrapper struct is used to */ /* avoid warnings about a duplicate volatile qualifier in case etype */ /* already includes it. */ #define init_exception_context(ec) ((void)((ec)->penv = 0)) #define Try \ { \ jmp_buf * volatile exception__prev; \ jmp_buf exception__env; \ exception__prev = the_exception_context->penv; \ the_exception_context->penv = &exception__env; \ if (setjmp(exception__env) == 0) { \ do #define exception__catch(action) \ while (the_exception_context->caught = 0, \ the_exception_context->caught); \ } \ else { \ the_exception_context->caught = 1; \ } \ the_exception_context->penv = exception__prev; \ } \ if (!the_exception_context->caught || action) { } \ else #define Catch(e) exception__catch(((e) = the_exception_context->v.etmp, 0)) #define Catch_anonymous exception__catch(0) /* Try ends with do, and Catch begins with while(0) and ends with */ /* else, to ensure that Try/Catch syntax is similar to if/else */ /* syntax. */ /* */ /* The 0 in while(0) is expressed as x=0,x in order to appease */ /* compilers that warn about constant expressions inside while(). */ /* Most compilers should still recognize that the condition is always */ /* false and avoid generating code for it. */ #define Throw \ for (;; longjmp(*the_exception_context->penv, 1)) \ the_exception_context->v.etmp = #endif /* CEXCEPT_H */ optipng-0.7.7/src/cexcept/example1.c000066400000000000000000000025441343170417500173210ustar00rootroot00000000000000/*=== cexcept: example1.c 2.0.0 (2001-Jul-12-Thu) Adam M. Costello An example application that demonstrates how to use version 2.0.* of the cexcept.h interface. See README for copyright information. This application is single-threaded and uses a global exception context. See example2.c for a demonstration of nested Try blocks, avoidance of global variables by passing the context in function arguments, and the use of a polymorphic exception type. ===*/ #include #include /* The following declarations would normally go in a separate .h file: */ #include "cexcept.h" define_exception_type(int); extern struct exception_context the_exception_context[1]; /* End of separate .h file. */ void demo_throw(int fail) { fprintf(stderr, "enter demo_throw(%d)\n", fail); if (fail) Throw 42; fprintf(stderr, "return from demo_throw(%d)\n", fail); } void foo(int fail) { fprintf(stderr, "enter foo(%d)\n", fail); demo_throw(fail); fprintf(stderr, "return from foo(%d)\n", fail); } /* Globally accessible storage for the exception context: */ struct exception_context the_exception_context[1]; int main() { int e; Try { foo(0); foo(1); foo(2); } Catch (e) fprintf(stderr, "exception %d\n", e); Try foo(3); Catch_anonymous fprintf(stderr, "anonymous exception\n"); return EXIT_SUCCESS; } optipng-0.7.7/src/cexcept/example2.c000066400000000000000000000056701343170417500173250ustar00rootroot00000000000000/*=== cexcept: example2.c 2.0.0 (2001-Mar-21-Wed) Adam M. Costello An example application that demonstrates how to use version 2.0.* of the cexcept.h interface to provide polymorphic exceptions, while avoiding the use of global variables. It also illustrates the use of dynamically nested Try blocks. See README for copyright information. See example.c for a simpler example. ===*/ #include #include #include /* The following declarations would normally go in a separate .h file: */ #include "cexcept.h" enum exception_flavor { okay, oops, screwup, barf }; struct exception { enum exception_flavor flavor; const char *msg; union { int oops; long screwup; char barf[8]; } info; }; define_exception_type(struct exception); /* End of separate .h file. */ struct thread_state { int blah; struct exception_context ec[1]; unsigned long junk; }; void demo_throw(struct exception_context *the_exception_context) { static int count = 0; struct exception e; fprintf(stderr, "enter demo_throw\n"); ++count; if (count == 2) { e.flavor = oops; e.msg = "demo oops message"; e.info.oops = 17; Throw e; } else if (count == 3) { e.flavor = barf; e.msg = "demo barf message"; strcpy(e.info.barf, "ABCDEFG"); Throw e; } else if (count == 4) { e.flavor = screwup; e.msg = "demo screwup message"; e.info.screwup = 987654321; Throw e; } fprintf(stderr, "return from demo_throw\n"); } void foo(struct thread_state *state) { fprintf(stderr, "enter foo\n"); demo_throw(state->ec); fprintf(stderr, "return from foo\n"); } void bar(struct thread_state *state) { struct exception_context *the_exception_context = state->ec; struct exception e; fprintf(stderr, "enter bar\n"); Try foo(state); Catch (e) { switch (e.flavor) { case okay: break; case oops: fprintf(stderr, "bar caught oops (info == %d): %s\n", e.info.oops, e.msg); break; default: Throw e; } } fprintf(stderr, "return from bar\n"); } int main() { struct thread_state state[1]; struct exception_context *the_exception_context = state->ec; struct exception e; init_exception_context(the_exception_context); Try { bar(state); /* no exceptions */ bar(state); /* exception will be caught by bar(), looks okay to us */ bar(state); /* bar() will rethrow the exception */ fprintf(stderr, "we won't get here\n"); } Catch (e) { switch (e.flavor) { case okay: break; case barf: fprintf(stderr, "main caught barf (info == %s): %s\n", e.info.barf, e.msg); break; case screwup: fprintf(stderr, "main caught screwup (info == %ld): %s\n", e.info.screwup, e.msg); default: fprintf(stderr, "main caught unknown exception\n"); } } return EXIT_SUCCESS; } optipng-0.7.7/src/cexcept/rationale000066400000000000000000000161031343170417500173360ustar00rootroot00000000000000cexcept: rationale 2.0.0 (2001-Jul-12-Thu) Adam M. Costello Rationale for some of the design decisions behind version 2.0.* of the cexcept.h interface. See README for copyright information. Questions answered below: * Why aren't multiple Catch clauses allowed? * Why can't I say Catch (int e) like in C++ or Java? * Why can't I jump into or out of a Try clause? * Why isn't a Finally clause supported? * Why can't I use Throw without an expression to re-throw an exception? * Why can't "real" exceptions be caught? * Why must the Catch expression have the same type that was passed to define_exception_type()? I can assign a double value to an int, so why can't I catch a double exception in an int variable? * Why does the implementation copy the exception twice? * Why are the macros spelled Try, Catch, Throw rather than...? Why aren't multiple Catch clauses allowed? The purpose of multiple catch clauses in C++ or Java is to allow you to catch multiple exception types. This is natural in a language that supports polymorphism, where you can substitute objects of different types into the same expression and cause different code to be executed. In such a language you can throw any type of object, and the appropriate catch clause will be selected automatically. C does not support polymorphism (except for unions and void pointers). Therefore it is natural in C to have just one exception type, and therefore one Catch clause is sufficient. The application programmer is free to use any type for the exception type, and may use a union to simulate polymorphism (see example2.c for an example of this). But for many applications an int, enum, or small struct will be sufficient. But couldn't tricks be played to allow multiple exception types? Yes, but cexcept.h is intended for C programs and C programmers. If the concept of polymorphism were incorporated into the interface, the interface would become less intuitive to many of the people it is designed for. But if an application programmer uses unions to simulate multiple exception types, the resulting code will be perfectly understandable to other C programmers, even if they have no experience with polymorphism. Why can't I say Catch (int e) like in C++ or Java? Again, the interface tries to be intuitive to C programmers. In C, declarations go at the beginnings of blocks. The cexcept syntax is actually more flexible in a way, because any lvalue can go in the parentheses, for example: Catch (p->e) Why can't I jump into or out of a Try clause? There is some hidden setup and cleanup that needs to be done regardless of whether an exception is caught. Jumping into a Try clause would avoid doing the setup, and jumping out of it would avoid doing the cleanup. Why isn't a Finally clause supported? There's no way to implement it. In Java, the main difference between putting code in a finally clause versus putting the code after the try/catch statement is that the finally clause will get executed even if a return or throw occurs within the try clause or catch clause. But in C, a return statement returns immediately. In Java one could make do without a finally clause by deferring any return from the try clause (by storing the return value in a variable), and moving some or all of the catch code outside the try/catch statement, like so: Exception e = null; try { ... } catch (Exception tmp) { e = tmp; } // Do cleanup here. if (e instanceof Foo) { ... } else if (e instanceof Bar) { ... } ... else if (e != null) throw e; A similar technique can be used with cexcept: my_exception_type e = some null value that will not be thrown; Try { ... } Catch (e) { } /* Do cleanup here. */ if (e is not that null value) { ... } Why can't I use Throw without an expression to re-throw an exception? The use of throw without an expression is needed in C++ because it's the only way to re-throw an exception of unknown type: catch (...) { // do some stuff throw; } This syntax is not provided in Java because the fact that all exceptions are instances of Exception eliminates the problem: catch (Exception e) { // do some stuff throw e; } Similarly, with cexcept, the type of exceptions is always known, so an expressionless Throw is not needed. Besides, the syntax would be very difficult, if not impossible, to implement. Why can't "real" exceptions be caught? "Real" exceptions (like floating-point exceptions and addressing exceptions) are platform-dependent, but cexcept is a platform-independent abstraction of setjmp/longjmp. The only way to jump to a setjmp() is from a longjmp(), so a Catch requires an explicit Throw. On POSIX systems, it is possible to call setjmp() from within a signal handler, and hence possible to use Throw within a signal handler, but this is very likely to cause subtle bugs and is not recommended. If a program uses both signals and cexcept, it may wish to modify cexcept.h to use the POSIX functions sigsetjmp() and siglongjmp() instead of the standard C library functions setjmp() and longjmp(). Why must the Catch expression have the same type that was passed to define_exception_type()? I can assign a double value to an int, so why can't I catch a double exception in an int variable? The intuitive expectation is that "Throw v" and "Catch (e)" should have an effect equivalent to "e = v". The latter converts v to the type of e, but the Throw statement has no way of knowing the type of e, so it converts v to the type passed to define_exception_type(). Depending on how cexcept is implemented, unintuitive or even undefined behavior could result if e has a different type. Why does the implementation copy the exception twice? The Throw statement must store the exception value somewhere. If it stores directly into the object named by the Catch expression, then that object must not be a non-volatile automatic object. It was deemed preferable to copy the exception twice rather than prohibit application programmers from catching exceptions in non-volatile automatic objects (which is what they would most often be inclined to use). Why are the macros spelled Try, Catch, Throw rather than...? We considered many other possibilities: try catch throw TRY CATCH THROW ctry ccatch cthrow c_try c_catch c_throw cex_try cex_catch cex_throw CEX_TRY CEX_CATCH CEX_THROW cexcept_try cexcept_catch cexcept_throw try_until_exception catch_exception throw_exception We wanted names that would be easy to read, easy to type, intuitive, and unlikely to conflict with existing names. Ultimately we settled on Try, Catch, and Throw as the best compromise among all these criteria. optipng-0.7.7/src/gifread/000077500000000000000000000000001343170417500154025ustar00rootroot00000000000000optipng-0.7.7/src/gifread/Doxyfile000066400000000000000000000254501343170417500171160ustar00rootroot00000000000000# Doxyfile 1.8.13 #--------------------------------------------------------------------------- # Project related configuration options #--------------------------------------------------------------------------- DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = gifread PROJECT_NUMBER = PROJECT_BRIEF = PROJECT_LOGO = OUTPUT_DIRECTORY = CREATE_SUBDIRS = NO ALLOW_UNICODE_NAMES = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES REPEAT_BRIEF = YES ABBREVIATE_BRIEF = ALWAYS_DETAILED_SEC = NO INLINE_INHERITED_MEMB = NO FULL_PATH_NAMES = YES STRIP_FROM_PATH = STRIP_FROM_INC_PATH = SHORT_NAMES = NO JAVADOC_AUTOBRIEF = YES QT_AUTOBRIEF = YES MULTILINE_CPP_IS_BRIEF = NO INHERIT_DOCS = YES SEPARATE_MEMBER_PAGES = NO TAB_SIZE = 8 ALIASES = TCL_SUBST = OPTIMIZE_OUTPUT_FOR_C = YES OPTIMIZE_OUTPUT_JAVA = NO OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO EXTENSION_MAPPING = MARKDOWN_SUPPORT = NO TOC_INCLUDE_HEADINGS = 0 AUTOLINK_SUPPORT = YES BUILTIN_STL_SUPPORT = NO CPP_CLI_SUPPORT = NO SIP_SUPPORT = NO IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO GROUP_NESTED_COMPOUNDS = NO SUBGROUPING = YES INLINE_GROUPED_CLASSES = NO INLINE_SIMPLE_STRUCTS = NO TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- EXTRACT_ALL = NO EXTRACT_PRIVATE = NO EXTRACT_PACKAGE = NO EXTRACT_STATIC = NO EXTRACT_LOCAL_CLASSES = YES EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO HIDE_UNDOC_MEMBERS = NO HIDE_UNDOC_CLASSES = NO HIDE_FRIEND_COMPOUNDS = NO HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO CASE_SENSE_NAMES = NO HIDE_SCOPE_NAMES = NO HIDE_COMPOUND_REFERENCE= NO SHOW_INCLUDE_FILES = YES SHOW_GROUPED_MEMB_INC = NO FORCE_LOCAL_INCLUDES = NO INLINE_INFO = YES SORT_MEMBER_DOCS = YES SORT_BRIEF_DOCS = NO SORT_MEMBERS_CTORS_1ST = NO SORT_GROUP_NAMES = NO SORT_BY_SCOPE_NAME = NO STRICT_PROTO_MATCHING = NO GENERATE_TODOLIST = YES GENERATE_TESTLIST = YES GENERATE_BUGLIST = YES GENERATE_DEPRECATEDLIST= YES ENABLED_SECTIONS = MAX_INITIALIZER_LINES = 30 SHOW_USED_FILES = YES SHOW_FILES = YES SHOW_NAMESPACES = YES FILE_VERSION_FILTER = LAYOUT_FILE = CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages #--------------------------------------------------------------------------- QUIET = NO WARNINGS = YES WARN_IF_UNDOCUMENTED = NO WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_AS_ERROR = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files #--------------------------------------------------------------------------- INPUT = INPUT_ENCODING = UTF-8 FILE_PATTERNS = RECURSIVE = NO EXCLUDE = EXCLUDE_SYMLINKS = NO EXCLUDE_PATTERNS = EXCLUDE_SYMBOLS = EXAMPLE_PATH = EXAMPLE_PATTERNS = EXAMPLE_RECURSIVE = NO IMAGE_PATH = INPUT_FILTER = FILTER_PATTERNS = FILTER_SOURCE_FILES = NO FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- SOURCE_BROWSER = NO INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES REFERENCED_BY_RELATION = NO REFERENCES_RELATION = NO REFERENCES_LINK_SOURCE = YES SOURCE_TOOLTIPS = YES USE_HTAGS = NO VERBATIM_HEADERS = YES #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- ALPHABETICAL_INDEX = YES COLS_IN_ALPHA_INDEX = 5 IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output #--------------------------------------------------------------------------- GENERATE_HTML = YES HTML_OUTPUT = html HTML_FILE_EXTENSION = .html HTML_HEADER = HTML_FOOTER = HTML_STYLESHEET = HTML_EXTRA_STYLESHEET = HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 HTML_TIMESTAMP = NO HTML_DYNAMIC_SECTIONS = NO HTML_INDEX_NUM_ENTRIES = 100 GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" DOCSET_BUNDLE_ID = org.doxygen.Project DOCSET_PUBLISHER_ID = org.doxygen.Publisher DOCSET_PUBLISHER_NAME = Publisher GENERATE_HTMLHELP = NO CHM_FILE = HHC_LOCATION = GENERATE_CHI = NO CHM_INDEX_ENCODING = BINARY_TOC = NO TOC_EXPAND = NO GENERATE_QHP = NO QCH_FILE = QHP_NAMESPACE = org.doxygen.Project QHP_VIRTUAL_FOLDER = doc QHP_CUST_FILTER_NAME = QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = QHG_LOCATION = GENERATE_ECLIPSEHELP = NO ECLIPSE_DOC_ID = org.doxygen.Project DISABLE_INDEX = NO GENERATE_TREEVIEW = NO ENUM_VALUES_PER_LINE = 4 TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES USE_MATHJAX = NO MATHJAX_FORMAT = HTML-CSS MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest MATHJAX_EXTENSIONS = MATHJAX_CODEFILE = SEARCHENGINE = YES SERVER_BASED_SEARCH = NO EXTERNAL_SEARCH = NO SEARCHENGINE_URL = SEARCHDATA_FILE = searchdata.xml EXTERNAL_SEARCH_ID = EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # Configuration options related to the LaTeX output #--------------------------------------------------------------------------- GENERATE_LATEX = NO LATEX_OUTPUT = latex LATEX_CMD_NAME = latex MAKEINDEX_CMD_NAME = makeindex COMPACT_LATEX = NO PAPER_TYPE = a4 EXTRA_PACKAGES = LATEX_HEADER = LATEX_FOOTER = LATEX_EXTRA_STYLESHEET = LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES USE_PDFLATEX = YES LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain LATEX_TIMESTAMP = NO #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- GENERATE_RTF = NO RTF_OUTPUT = rtf COMPACT_RTF = NO RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = RTF_SOURCE_CODE = NO #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- GENERATE_MAN = NO MAN_OUTPUT = man MAN_EXTENSION = .3 MAN_SUBDIR = MAN_LINKS = NO #--------------------------------------------------------------------------- # Configuration options related to the XML output #--------------------------------------------------------------------------- GENERATE_XML = NO XML_OUTPUT = xml XML_PROGRAMLISTING = YES #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook DOCBOOK_PROGRAMLISTING = NO #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- GENERATE_AUTOGEN_DEF = NO #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- GENERATE_PERLMOD = NO PERLMOD_LATEX = NO PERLMOD_PRETTY = YES PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- ENABLE_PREPROCESSING = YES MACRO_EXPANSION = NO EXPAND_ONLY_PREDEF = NO SEARCH_INCLUDES = YES INCLUDE_PATH = INCLUDE_FILE_PATTERNS = PREDEFINED = EXPAND_AS_DEFINED = SKIP_FUNCTION_MACROS = YES #--------------------------------------------------------------------------- # Configuration options related to external references #--------------------------------------------------------------------------- TAGFILES = GENERATE_TAGFILE = ALLEXTERNALS = NO EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- CLASS_DIAGRAMS = YES MSCGEN_PATH = DIA_PATH = HIDE_UNDOC_RELATIONS = YES HAVE_DOT = NO DOT_NUM_THREADS = 0 DOT_FONTNAME = Helvetica DOT_FONTSIZE = 10 DOT_FONTPATH = CLASS_GRAPH = YES COLLABORATION_GRAPH = YES GROUP_GRAPHS = YES UML_LOOK = NO UML_LIMIT_NUM_FIELDS = 10 TEMPLATE_RELATIONS = NO INCLUDE_GRAPH = YES INCLUDED_BY_GRAPH = YES CALL_GRAPH = NO CALLER_GRAPH = NO GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES DOT_IMAGE_FORMAT = png INTERACTIVE_SVG = NO DOT_PATH = DOTFILE_DIRS = MSCFILE_DIRS = DIAFILE_DIRS = PLANTUML_JAR_PATH = PLANTUML_CFG_FILE = PLANTUML_INCLUDE_PATH = DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 DOT_TRANSPARENT = NO DOT_MULTI_TARGETS = NO GENERATE_LEGEND = YES DOT_CLEANUP = YES optipng-0.7.7/src/gifread/Makefile.in000066400000000000000000000020201343170417500174410ustar00rootroot00000000000000.PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = @CC@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ LD = @LD@ LDFLAGS = @LDFLAGS@ AR = @AR@ ARFLAGS = @ARFLAGS@ RANLIB = @RANLIB@ LIBS = @LIBS@ RM_F = @RM_F@ GIFREAD_LIB = libgifread.a GIFREAD_OBJS = gifread.o GIFDUMP = test/gifdump$(EXEEXT) GIFDUMP_OBJS = test/gifdump.o GIFDUMP_OUT = test/*.gifdump.out all: $(GIFREAD_LIB) $(GIFDUMP) test: $(GIFDUMP) $(GIFDUMP) img/compass.gif > test/compass.gifdump.out -@echo gifdump test ... ok check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< $(GIFREAD_LIB): $(GIFREAD_OBJS) $(AR) $(ARFLAGS) $@ $(GIFREAD_OBJS) $(RANLIB) $@ $(GIFDUMP): $(GIFDUMP_OBJS) $(GIFREAD_LIB) $(LD) $(LDFLAGS) -o $@ $(GIFDUMP_OBJS) $(GIFREAD_LIB) $(LIBS) gifread.o: gifread.c gifread.h test/gifdump.o: test/gifdump.c gifread.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o $@ $*.c clean: -$(RM_F) $(GIFREAD_LIB) $(GIFREAD_OBJS) -$(RM_F) $(GIFDUMP) $(GIFDUMP_OBJS) $(GIFDUMP_OUT) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/gifread/README.optipng.txt000066400000000000000000000001411343170417500205530ustar00rootroot00000000000000Name: gifread Summary: A simple GIF reader Author: Cosmin Truta License: BSD-like; see gifread.h optipng-0.7.7/src/gifread/build/000077500000000000000000000000001343170417500165015ustar00rootroot00000000000000optipng-0.7.7/src/gifread/build/bcc32.mk000066400000000000000000000021211343170417500177220ustar00rootroot00000000000000# bcc32.mk # Generated from Makefile.in # Preconfigured for Borland C++ # # Usage: make -f build\bcc32.mk CC = bcc32 CFLAGS = -O2 -d -k- -w CPP = #cpp32 -P- CPPFLAGS = LD = $(CC) LDFLAGS = $(CFLAGS) AR = tlib ARFLAGS = /C LIBS = #noeh32.lib RM_F = del /q GIFREAD_LIB = gifread.lib GIFREAD_OBJS = gifread.obj GIFREAD_LIBOBJS = +gifread.obj GIFDUMP = test\gifdump.exe GIFDUMP_OBJS = test\gifdump.obj GIFDUMP_LIBOBJS = test\+gifdump.obj GIFDUMP_OUT = test\*.gifdump.out all: $(GIFREAD_LIB) $(GIFDUMP) test: $(GIFDUMP) $(GIFDUMP) img\compass.gif > test\compass.gifdump.out -@echo gifdump test ... ok check: test .c.obj: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o$@ $< $(GIFREAD_LIB): $(GIFREAD_OBJS) $(AR) $(ARFLAGS) $@ $(GIFREAD_LIBOBJS) $(GIFDUMP): $(GIFDUMP_OBJS) $(GIFREAD_LIB) $(LD) $(LDFLAGS) -e$@ $(GIFDUMP_OBJS) $(GIFREAD_LIB) $(LIBS) gifread.obj: gifread.c gifread.h test\gifdump.obj: test\gifdump.c gifread.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o$@ $*.c clean: -$(RM_F) $(GIFREAD_LIB) $(GIFREAD_OBJS) -$(RM_F) $(GIFDUMP) $(GIFDUMP_OBJS) $(GIFDUMP_OUT) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/gifread/build/clang.mk000066400000000000000000000021371343170417500201210ustar00rootroot00000000000000# clang.mk # Generated from Makefile.in # Preconfigured for clang # # Usage: make -f build/clang.mk .PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = clang CFLAGS = -O2 -Wall -Wextra CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s AR = ar ARFLAGS = cru RANLIB = ranlib LIBS = RM_F = rm -f GIFREAD_LIB = libgifread.a GIFREAD_OBJS = gifread.o GIFDUMP = test/gifdump$(EXEEXT) GIFDUMP_OBJS = test/gifdump.o GIFDUMP_OUT = test/*.gifdump.out all: $(GIFREAD_LIB) $(GIFDUMP) test: $(GIFDUMP) $(GIFDUMP) img/compass.gif > test/compass.gifdump.out -@echo gifdump test ... ok check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< $(GIFREAD_LIB): $(GIFREAD_OBJS) $(AR) $(ARFLAGS) $@ $(GIFREAD_OBJS) $(RANLIB) $@ $(GIFDUMP): $(GIFDUMP_OBJS) $(GIFREAD_LIB) $(LD) $(LDFLAGS) -o $@ $(GIFDUMP_OBJS) $(GIFREAD_LIB) $(LIBS) gifread.o: gifread.c gifread.h test/gifdump.o: test/gifdump.c gifread.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o $@ $*.c clean: -$(RM_F) $(GIFREAD_LIB) $(GIFREAD_OBJS) -$(RM_F) $(GIFDUMP) $(GIFDUMP_OBJS) $(GIFDUMP_OUT) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/gifread/build/gcc.mk000066400000000000000000000021271343170417500175700ustar00rootroot00000000000000# gcc.mk # Generated from Makefile.in # Preconfigured for gcc # # Usage: make -f build/gcc.mk .PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = gcc CFLAGS = -O2 -Wall -Wextra CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s AR = ar ARFLAGS = cru RANLIB = ranlib LIBS = RM_F = rm -f GIFREAD_LIB = libgifread.a GIFREAD_OBJS = gifread.o GIFDUMP = test/gifdump$(EXEEXT) GIFDUMP_OBJS = test/gifdump.o GIFDUMP_OUT = test/*.gifdump.out all: $(GIFREAD_LIB) $(GIFDUMP) test: $(GIFDUMP) $(GIFDUMP) img/compass.gif > test/compass.gifdump.out -@echo gifdump test ... ok check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< $(GIFREAD_LIB): $(GIFREAD_OBJS) $(AR) $(ARFLAGS) $@ $(GIFREAD_OBJS) $(RANLIB) $@ $(GIFDUMP): $(GIFDUMP_OBJS) $(GIFREAD_LIB) $(LD) $(LDFLAGS) -o $@ $(GIFDUMP_OBJS) $(GIFREAD_LIB) $(LIBS) gifread.o: gifread.c gifread.h test/gifdump.o: test/gifdump.c gifread.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o $@ $*.c clean: -$(RM_F) $(GIFREAD_LIB) $(GIFREAD_OBJS) -$(RM_F) $(GIFDUMP) $(GIFDUMP_OBJS) $(GIFDUMP_OUT) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/gifread/build/unix.mk000066400000000000000000000021241343170417500200140ustar00rootroot00000000000000# unix.mk # Generated from Makefile.in # Preconfigured for Unix (generic) # # Usage: make -f build/unix.mk .PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = cc CFLAGS = -O CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s AR = ar ARFLAGS = cru RANLIB = ranlib LIBS = RM_F = rm -f GIFREAD_LIB = libgifread.a GIFREAD_OBJS = gifread.o GIFDUMP = test/gifdump$(EXEEXT) GIFDUMP_OBJS = test/gifdump.o GIFDUMP_OUT = test/*.gifdump.out all: $(GIFREAD_LIB) $(GIFDUMP) test: $(GIFDUMP) $(GIFDUMP) img/compass.gif > test/compass.gifdump.out -@echo gifdump test ... ok check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< $(GIFREAD_LIB): $(GIFREAD_OBJS) $(AR) $(ARFLAGS) $@ $(GIFREAD_OBJS) $(RANLIB) $@ $(GIFDUMP): $(GIFDUMP_OBJS) $(GIFREAD_LIB) $(LD) $(LDFLAGS) -o $@ $(GIFDUMP_OBJS) $(GIFREAD_LIB) $(LIBS) gifread.o: gifread.c gifread.h test/gifdump.o: test/gifdump.c gifread.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o $@ $*.c clean: -$(RM_F) $(GIFREAD_LIB) $(GIFREAD_OBJS) -$(RM_F) $(GIFDUMP) $(GIFDUMP_OBJS) $(GIFDUMP_OUT) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/gifread/build/visualc.mk000066400000000000000000000021251343170417500205000ustar00rootroot00000000000000# visualc.mk # Generated from Makefile.in # Preconfigured for Microsoft Visual C++ # # Usage: nmake -f build\visualc.mk CC = cl -nologo CFLAGS = -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -MD -O2 -W4 CPP = cl -nologo -E CPPFLAGS = LD = link -nologo LDFLAGS = AR = lib -nologo ARFLAGS = LIBS = RM_F = del /q GIFREAD_LIB = gifread.lib GIFREAD_OBJS = gifread.obj GIFDUMP = test\gifdump.exe GIFDUMP_OBJS = test\gifdump.obj GIFDUMP_OUT = test\*.gifdump.out all: $(GIFREAD_LIB) $(GIFDUMP) test: $(GIFDUMP) $(GIFDUMP) img\compass.gif > test\compass.gifdump.out -@echo gifdump test ... ok check: test .c.obj: $(CC) -c $(CPPFLAGS) $(CFLAGS) -Fo$@ $< $(GIFREAD_LIB): $(GIFREAD_OBJS) $(AR) $(ARFLAGS) -out:$@ $(GIFREAD_OBJS) $(GIFDUMP): $(GIFDUMP_OBJS) $(GIFREAD_LIB) $(LD) $(LDFLAGS) -out:$@ $(GIFDUMP_OBJS) $(GIFREAD_LIB) $(LIBS) gifread.obj: gifread.c gifread.h test\gifdump.obj: test\gifdump.c gifread.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -Fo$@ $*.c clean: -$(RM_F) $(GIFREAD_LIB) $(GIFREAD_OBJS) -$(RM_F) $(GIFDUMP) $(GIFDUMP_OBJS) $(GIFDUMP_OUT) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/gifread/gifread.c000066400000000000000000000446351343170417500171630ustar00rootroot00000000000000/* * gifread.c * A simple GIF reader. * * Copyright (C) 2003-2017 Cosmin Truta. * This software was derived from "giftopnm.c" by David Koblas, * and is distributed under the same copyright and warranty terms. * * The original copyright notice is provided below. * * Copyright 1990 - 1994, David Koblas. (koblas@netcom.com) * Permission to use, copy, modify, and distribute this software * and its documentation for any purpose and without fee is hereby * granted, provided that the above copyright notice appear in all * copies and that both that copyright notice and this permission * notice appear in supporting documentation. This software is * provided "as is" without express or implied warranty. */ #include "gifread.h" #include #include #include #include #if UCHAR_MAX != 255 #error This module requires 8-bit bytes. #endif #ifdef GIF_DEBUG #define GIF_TRACE(args) (printf args) #else #define GIF_TRACE(args) ((void)0) #endif #define GIF_MEMGETW(buffer) ((buffer)[0] + ((buffer)[1] << 8)) #define LZW_FALSE 0 #define LZW_TRUE 1 #define LZW_BITS_MAX 12 #define LZW_CODE_MAX ((1 << LZW_BITS_MAX) - 1) static void GIFReadNextImage(struct GIFImage *image, FILE *stream); static void GIFReadImageData(struct GIFImage *image, FILE *stream); static int GIFReadDataBlock(unsigned char *buffer, FILE *stream); static void GIFSkipDataBlocks(FILE *stream); static int LZWGetCode(int code_size, int init_flag, FILE *stream); static int LZWDecodeByte(int init_flag, int input_code_size, FILE *stream); static void GIFReadNextExtension(struct GIFExtension *ext, FILE *stream); static int GetByte(FILE *stream); static void ReadBytes(unsigned char *buffer, unsigned int count, FILE *stream); static void ErrorAlloc(void); static void ErrorRead(FILE *stream); static void DefaultError(const char *message); static void DefaultWarning(const char *message); /* * Reads the GIF screen and the global color table. */ void GIFReadScreen(struct GIFScreen *screen, FILE *stream) { unsigned char buffer[7]; GIF_TRACE(("Reading Header\n")); ReadBytes(buffer, 6, stream); if (memcmp(buffer, "GIF", 3) != 0) GIFError("Not a GIF file"); if ((memcmp(buffer + 3, "87a", 3) != 0) && (memcmp(buffer + 3, "89a", 3) != 0)) GIFWarning("Invalid GIF version number, not \"87a\" or \"89a\""); GIF_TRACE(("Reading Logical Screen Descriptor\n")); ReadBytes(buffer, 7, stream); screen->Width = GIF_MEMGETW(buffer + 0); screen->Height = GIF_MEMGETW(buffer + 2); screen->GlobalColorFlag = (buffer[4] & 0x80) ? 1 : 0; screen->ColorResolution = ((buffer[4] & 0x70) >> 3) + 1; screen->SortFlag = (buffer[4] & 0x08) ? 1 : 0; screen->GlobalNumColors = 2 << (buffer[4] & 0x07); screen->Background = buffer[5]; screen->PixelAspectRatio = buffer[6]; if (screen->GlobalColorFlag) { GIF_TRACE(("Reading Global Color Table\n")); ReadBytes(screen->GlobalColorTable, 3 * screen->GlobalNumColors, stream); } GIF_TRACE(("Validating Logical Screen Descriptor\n")); if (screen->Width == 0 || screen->Height == 0) GIFError("Invalid dimensions in GIF image"); if (screen->Background > 0) { if ((screen->GlobalColorFlag && (screen->Background >= screen->GlobalNumColors)) || !screen->GlobalColorFlag) { #if 0 /* too noisy */ GIFWarning("Invalid background color index in GIF image"); #endif screen->Background = 0; } } } /* * Initializes a GIF image object. */ void GIFInitImage(struct GIFImage *image, struct GIFScreen *screen, unsigned char **rows) { image->Screen = screen; image->Rows = rows; } /* * Destroys a GIF image object. */ void GIFDestroyImage(struct GIFImage *image) { (void)image; /* nothing to do */ } /* * Reads the next GIF block into an image or extension object. */ int GIFReadNextBlock(struct GIFImage *image, struct GIFExtension *ext, FILE *stream) { int ch; int foundBogus; foundBogus = 0; for ( ; ; ) { ch = GetByte(stream); switch (ch) { case GIF_IMAGE: /* ',' */ GIFReadNextImage(image, stream); return ch; case GIF_EXTENSION: /* '!' */ GIFReadNextExtension(ext, stream); return ch; case GIF_TERMINATOR: /* ';' */ return ch; default: if (!foundBogus) GIFWarning("Bogus data in GIF file"); foundBogus = 1; } } } /* * Reads the next GIF image and local color table. */ static void GIFReadNextImage(struct GIFImage *image, FILE *stream) { struct GIFScreen *screen; unsigned char buffer[9]; GIF_TRACE(("Reading Local Image Descriptor\n")); ReadBytes(buffer, 9, stream); if (image == NULL) { GIFSkipDataBlocks(stream); return; } image->LeftPos = GIF_MEMGETW(buffer + 0); image->TopPos = GIF_MEMGETW(buffer + 2); image->Width = GIF_MEMGETW(buffer + 4); image->Height = GIF_MEMGETW(buffer + 6); image->LocalColorFlag = (buffer[8] & 0x80) ? 1 : 0; image->InterlaceFlag = (buffer[8] & 0x40) ? 1 : 0; image->SortFlag = (buffer[8] & 0x20) ? 1 : 0; image->LocalNumColors = image->LocalColorFlag ? (2 << (buffer[8] & 0x07)) : 0; if (image->LocalColorFlag) { GIF_TRACE(("Reading Local Color Table\n")); ReadBytes(image->LocalColorTable, 3 * image->LocalNumColors, stream); } GIF_TRACE(("Validating Logical Screen Descriptor\n")); screen = image->Screen; if (image->Width == 0 || image->Height == 0 || image->LeftPos + image->Width > screen->Width || image->TopPos + image->Height > screen->Height) GIFError("Invalid dimensions in GIF image"); GIFReadImageData(image, stream); } static void GIFReadImageData(struct GIFImage *image, FILE *stream) { int minCodeSize; unsigned char **rows; unsigned int width, height, interlaced; unsigned char *colors; unsigned int numColors; unsigned int xpos, ypos; int pass, val; GIF_TRACE(("Reading Image Data\n")); /* Initialize the compression routines. */ minCodeSize = GetByte(stream); if (minCodeSize >= LZW_BITS_MAX) GIFError("Invalid LZW code size"); if (LZWDecodeByte(LZW_TRUE, minCodeSize, stream) < 0) GIFError("Error decoding GIF image"); /* Ignore the picture if it is "uninteresting". */ rows = image->Rows; if (rows == NULL) { #if 0 while (LZWDecodeByte(LZW_FALSE, minCodeSize, stream) >= 0) { } #else /* This is faster, but possible LZW errors may go undetected. */ GIFSkipDataBlocks(stream); #endif return; } width = image->Width; height = image->Height; interlaced = image->InterlaceFlag; GIFGetColorTable(&colors, &numColors, image); xpos = ypos = 0; pass = 0; while ((val = LZWDecodeByte(LZW_FALSE, minCodeSize, stream)) >= 0) { if ((unsigned int)val >= numColors) { GIFWarning("Pixel value out of range in GIF image"); val = numColors - 1; } rows[ypos][xpos] = (unsigned char)val; if (++xpos == width) { xpos = 0; if (interlaced) { switch (pass) { case 0: case 1: ypos += 8; break; case 2: ypos += 4; break; case 3: ypos += 2; break; } if (ypos >= height) { switch (++pass) { case 1: ypos = 4; break; case 2: ypos = 2; break; case 3: ypos = 1; break; default: goto fini; } } } else ++ypos; } if (ypos >= height) break; } fini: /* Ignore the trailing garbage. */ while (LZWDecodeByte(LZW_FALSE, minCodeSize, stream) >= 0) { } } static int DataBlockSize = 0; static int GIFReadDataBlock(unsigned char *buffer, FILE *stream) { int count; count = GetByte(stream); DataBlockSize = count; if (count > 0) ReadBytes(buffer, count, stream); return count; } static void GIFSkipDataBlocks(FILE *stream) { int count; unsigned char buffer[256]; for ( ; ; ) { count = GetByte(stream); if (count > 0) ReadBytes(buffer, count, stream); else return; } } static int LZWGetCode(int code_size, int init_flag, FILE *stream) { static unsigned char buffer[280]; static int curbit, lastbit, done, last_byte; int count, i, j, ret; if (init_flag) { curbit = 0; lastbit = 0; last_byte = 2; done = LZW_FALSE; return 0; } if ((curbit + code_size) >= lastbit) { if (done) { if (curbit >= lastbit) GIFError("Ran off the end of input bits in LZW decoding"); return -1; } buffer[0] = buffer[last_byte - 2]; buffer[1] = buffer[last_byte - 1]; if ((count = GIFReadDataBlock(&buffer[2], stream)) == 0) done = LZW_TRUE; last_byte = 2 + count; curbit = (curbit - lastbit) + 16; lastbit = (2 + count) * 8; } ret = 0; for (i = curbit, j = 0; j < code_size; ++i, ++j) ret |= ((buffer[i / 8] & (1 << (i % 8))) != 0) << j; curbit += code_size; return ret; } static int LZWDecodeByte(int init_flag, int input_code_size, FILE *stream) { static int fresh = LZW_FALSE; static int code_size, set_code_size; static int max_code, max_code_size; static int firstcode, oldcode; static int clear_code, end_code; static int table[2][LZW_CODE_MAX + 1]; static int stack[(LZW_CODE_MAX + 1) * 2], *sp; int code, incode; int i; if (init_flag) { fresh = LZW_TRUE; set_code_size = input_code_size; code_size = set_code_size + 1; clear_code = 1 << set_code_size; end_code = clear_code + 1; max_code_size = 2 * clear_code; max_code = clear_code + 2; LZWGetCode(0, LZW_TRUE, stream); for (i = 0; i < clear_code; ++i) { table[0][i] = 0; table[1][i] = i; } for ( ; i <= LZW_CODE_MAX; ++i) { table[0][i] = 0; table[1][i] = 0; } sp = stack; return 0; } else if (fresh) { fresh = LZW_FALSE; do { firstcode = oldcode = LZWGetCode(code_size, LZW_FALSE, stream); } while (firstcode == clear_code); return firstcode; } if (sp > stack) return *--sp; while ((code = LZWGetCode(code_size, LZW_FALSE, stream)) >= 0) { if (code == clear_code) { for (i = 0; i < clear_code; ++i) { table[0][i] = 0; table[1][i] = i; } for ( ; i <= LZW_CODE_MAX; ++i) { table[0][i] = 0; table[1][i] = 0; } code_size = set_code_size + 1; max_code_size = 2 * clear_code; max_code = clear_code + 2; sp = stack; firstcode = oldcode = LZWGetCode(code_size, LZW_FALSE, stream); return firstcode; } else if (code == end_code) { int count; unsigned char buffer[260]; if (DataBlockSize == 0) return -2; while ((count = GIFReadDataBlock(buffer, stream)) > 0) { } #if 0 /* too noisy */ if (count != 0) GIFWarning("Missing EOD in LZW data stream"); #else (void)count; #endif return -2; } incode = code; if (code >= max_code) { *sp++ = firstcode; code = oldcode; } while (code >= clear_code) { *sp++ = table[1][code]; if ((code == table[0][code]) || ((size_t)(sp - stack) >= sizeof(stack) / sizeof(stack[0]))) GIFError("Circular dependency found in LZW table"); code = table[0][code]; } *sp++ = firstcode = table[1][code]; if ((code = max_code) <= LZW_CODE_MAX) { table[0][code] = oldcode; table[1][code] = firstcode; ++max_code; if ((max_code >= max_code_size) && (max_code_size <= LZW_CODE_MAX)) { max_code_size *= 2; ++code_size; } } oldcode = incode; if (sp > stack) return *--sp; } return code; } /* * The GIF spec says that if neither global nor local * color maps are present, the decoder should use a system * default map, which should have black and white as the * first two colors. So we use black, white, red, green, blue, * yellow, purple and cyan. * Missing color tables are not a common case, and are not * handled by most GIF readers. */ static unsigned char DefaultColorTable[] = { 0, 0, 0, /* black */ 255, 255, 255, /* white */ 255, 0, 0, /* red */ 0, 255, 255, /* cyan */ 0, 255, 0, /* green */ 255, 0, 255, /* purple */ 0, 0, 255, /* blue */ 255, 255, 0, /* yellow */ }; /* * Returns the local or the global color table (whichever is applicable), * or a predefined color table if both of these tables are missing. */ void GIFGetColorTable(unsigned char **colors, unsigned int *numColors, struct GIFImage *image) { struct GIFScreen *screen; if (image->LocalColorFlag) { GIF_TRACE(("Loading Local Color Table\n")); *colors = image->LocalColorTable; *numColors = image->LocalNumColors; return; } screen = image->Screen; if (screen->GlobalColorFlag) { GIF_TRACE(("Loading Global Color Table\n")); *colors = screen->GlobalColorTable; *numColors = screen->GlobalNumColors; return; } GIF_TRACE(("Loading Default Color Table\n")); *colors = DefaultColorTable; *numColors = sizeof(DefaultColorTable) / 3; } /* * Initializes a GIF extension object. */ void GIFInitExtension(struct GIFExtension *ext, struct GIFScreen *screen, unsigned int initBufferSize) { unsigned char *newBuffer; ext->Screen = screen; if (initBufferSize > 0) { newBuffer = (unsigned char *)malloc(initBufferSize); if (newBuffer == NULL) ErrorAlloc(); ext->Buffer = newBuffer; ext->BufferSize = initBufferSize; } else { ext->Buffer = NULL; ext->BufferSize = 0; } } /* * Destroys a GIF extension object. */ void GIFDestroyExtension(struct GIFExtension *ext) { free(ext->Buffer); } /* * Reads the next GIF extension. */ static void GIFReadNextExtension(struct GIFExtension *ext, FILE *stream) { unsigned char *newBuffer; unsigned int newBufferSize; unsigned int offset, len; int count, label; label = GetByte(stream); GIF_TRACE(("Reading Extension (0x%X)\n", label)); if (ext == NULL) { GIFSkipDataBlocks(stream); return; } ext->Label = (unsigned char)label; offset = 0; len = ext->BufferSize; for ( ; ; ) { if (len < 255) { newBufferSize = ext->BufferSize + 1024; newBuffer = (unsigned char *)realloc(ext->Buffer, newBufferSize); if (newBuffer == NULL) ErrorAlloc(); ext->BufferSize = newBufferSize; ext->Buffer = newBuffer; len += 1024; } count = GIFReadDataBlock(ext->Buffer + offset, stream); if (count == 0) break; offset += count; len -= count; } } /* * Constructs a GIF graphic control extension object * from a raw extension object. */ void GIFGetGraphicCtl(struct GIFGraphicCtlExt *graphicExt, struct GIFExtension *ext) { unsigned char *buffer; GIF_TRACE(("Loading Graphic Control Extension\n")); if (ext->Label != GIF_GRAPHICCTL) { GIFWarning("Not a graphic control extension in GIF file"); return; } if (ext->BufferSize < 4) { GIFWarning("Broken graphic control extension in GIF file"); return; } buffer = ext->Buffer; graphicExt->DisposalMethod = (buffer[0] >> 2) & 0x07; graphicExt->InputFlag = (buffer[0] >> 1) & 0x01; graphicExt->TransparentFlag = buffer[0] & 0x01; graphicExt->DelayTime = GIF_MEMGETW(buffer + 1); graphicExt->Transparent = buffer[3]; } /* * Reads a byte. */ static int GetByte(FILE *stream) { int ch; if ((ch = getc(stream)) == EOF) ErrorRead(stream); return ch; } /* * Reads a sequence of bytes. */ static void ReadBytes(unsigned char *buffer, unsigned int count, FILE *stream) { if (fread(buffer, count, 1, stream) != 1) ErrorRead(stream); } /* * Fails with an out-of-memory error. */ static void ErrorAlloc(void) { GIFError("Out of memory in GIF decoder"); } /* * Fails with a read error. */ static void ErrorRead(FILE *stream) { if (ferror(stream)) GIFError("Error reading GIF file"); else GIFError("Unexpected end of GIF file"); } /* * The default error handler. */ static void DefaultError(const char *message) { fprintf(stderr, "%s\n", message); exit(EXIT_FAILURE); } /* * The default warning handler. */ static void DefaultWarning(const char *message) { fprintf(stderr, "%s\n", message); } /* * The error handling callback. */ void (*GIFError)(const char *message) = DefaultError; /* * The warning handling callback. */ void (*GIFWarning)(const char *message) = DefaultWarning; optipng-0.7.7/src/gifread/gifread.h000066400000000000000000000115701343170417500171600ustar00rootroot00000000000000/** * @file gifread.h * A simple GIF reader. * * @copyright *
 * Copyright (C) 2003-2017 Cosmin Truta.
 * This software was derived from "giftopnm.c" by David Koblas,
 * and is distributed under the same copyright and warranty terms.
 * 
 * The original copyright notice is provided below.
 * 
 * Copyright 1990 - 1994, David Koblas.  (koblas@netcom.com)
 *   Permission to use, copy, modify, and distribute this software
 *   and its documentation for any purpose and without fee is hereby
 *   granted, provided that the above copyright notice appear in all
 *   copies and that both that copyright notice and this permission
 *   notice appear in supporting documentation.  This software is
 *   provided "as is" without express or implied warranty.
 * 
* * @bug GIF/LZW decoding is not reentrant. **/ #ifndef GIFREAD_H_ #define GIFREAD_H_ #include #ifdef __cplusplus extern "C" { #endif #define GIF_PLAINTEXT 0x01 #define GIF_EXTENSION 0x21 /* '!' */ #define GIF_IMAGE 0x2c /* ',' */ #define GIF_TERMINATOR 0x3b /* ';' */ #define GIF_GRAPHICCTL 0xf9 #define GIF_COMMENT 0xfe #define GIF_APPLICATION 0xff #define GIF_NUMCOLORS_MAX 256 #define GIF_IND_RED 0 #define GIF_IND_GREEN 1 #define GIF_IND_BLUE 2 /** * The GIF screen structure. **/ struct GIFScreen { unsigned int Width; unsigned int Height; unsigned int GlobalColorFlag; unsigned int ColorResolution; unsigned int SortFlag; unsigned int GlobalNumColors; unsigned int Background; unsigned int PixelAspectRatio; unsigned char GlobalColorTable[GIF_NUMCOLORS_MAX * 3]; }; /** * The GIF image structure. **/ struct GIFImage { struct GIFScreen *Screen; unsigned int LeftPos; unsigned int TopPos; unsigned int Width; unsigned int Height; unsigned int LocalColorFlag; unsigned int InterlaceFlag; unsigned int SortFlag; unsigned int LocalNumColors; unsigned char LocalColorTable[GIF_NUMCOLORS_MAX * 3]; unsigned char **Rows; }; /** * The GIF extension structure. **/ struct GIFExtension { struct GIFScreen *Screen; unsigned char *Buffer; unsigned int BufferSize; unsigned char Label; }; /** * The GIF graphic control extension structure. **/ struct GIFGraphicCtlExt { unsigned int DisposalMethod; unsigned int InputFlag; unsigned int TransparentFlag; unsigned int DelayTime; unsigned int Transparent; }; /** * Reads the GIF screen and the global color table. * @param screen the destination screen object * @param stream a file stream **/ void GIFReadScreen(struct GIFScreen *screen, FILE *stream); /** * Initializes a GIF image object. * @param image the resulting image object * @param screen a screen object * @param rows an array of rows; can be NULL **/ void GIFInitImage(struct GIFImage *image, struct GIFScreen *screen, unsigned char **rows); /** * Destroys a GIF image object. * @param image an image object **/ void GIFDestroyImage(struct GIFImage *image); /** * Reads the next GIF block into an image or extension object. * @param image the destination image object; can be NULL * @param ext the destination extension object; can be NULL * @param stream a file stream * @return the block code **/ int GIFReadNextBlock(struct GIFImage *image, struct GIFExtension *ext, FILE *stream); /** * Returns the local or the global color table (whichever is applicable), * or a predefined color table if both of these tables are missing. * @param colors the resulting color table * @param numColors the size of the resulting color table * @param image an image object **/ void GIFGetColorTable(unsigned char **colors, unsigned int *numColors, struct GIFImage *image); /** * Initializes a GIF extension object. * @param ext the resulting extension object * @param screen a screen object * @param initBufferSize an initial buffer size; can be 0 **/ void GIFInitExtension(struct GIFExtension *ext, struct GIFScreen *screen, unsigned int initBufferSize); /** * Destroys a GIF extension object. * @param ext an extension object **/ void GIFDestroyExtension(struct GIFExtension *ext); /** * Constructs a GIF graphic control extension object * from a raw extension object. * @param graphicExt the resulting graphic control extension object * @param ext a raw extension object **/ void GIFGetGraphicCtl(struct GIFGraphicCtlExt *graphicExt, struct GIFExtension *ext); /** * The error handling callback. * @param message an error message **/ extern void (*GIFError)(const char *message); /** * The warning handling callback. * @param message a warning message **/ extern void (*GIFWarning)(const char *message); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* GIFREAD_H_ */ optipng-0.7.7/src/gifread/img/000077500000000000000000000000001343170417500161565ustar00rootroot00000000000000optipng-0.7.7/src/gifread/img/compass.gif000066400000000000000000001572021343170417500203210ustar00rootroot00000000000000GIF89a<<"""3ffUUU̙fDDDwwwf̙f33f33fff̙f3f! NETSCAPE2.0! ,<< di0EKBpδxx7$cH xȤFh:hptu,aL.ˏ1$B-D 縜e㏇ z@Xpyiwu`/%c&)cy"abejpdic/Q1$}exfcª$"jsqӫ2 sʼ&_}8 agL0}ϓv ,(X=eg*3 DҤ2cR H% (Xhe  Čy`==S)FO*7 DqtjufN(葠@pVZMPk&Et*hdN @"G (ڦ ]9)һW0"ZA 4RHcxa@ܭ /[<3MpV`Cl˅`y@z@p#?`+PYqq@ @98.ܐtK$`P͒;_uYT,4mɔ' wc.!G(h~Fp(X=`huؑ'Ja#X$`lݤ`JR0+Ba>L@ybl,3JWATP JT'1Fr*d0=&ev{@Y eryJG@ ¦waVd Q"!kk4 Mc )B-p)DObze3;&~,@ RH^?`KBgH$N.BˬE?!A|hX\` ŸH( 8,@bs 0kŋP(]yW|. W7 WO0{vae^_nR&VK$e :^N0A\<-X!8S<r ,g*f=Z\r'<ތC.ȝ3!'WW6 (T'ԃAQgà g0wSDi20+1a_v`7A~'msG  ۹_5LmMfT!|" Zd&!\ V,y AE#Hj yyEV)~2*@I)lTD**HN:R$$EB`*WV򕰌*E Z.wK>! ,<< di@d)axH(+al:aP0 Ьց( x<~B!p87IͱQ~gv`s^u%.o&)*f*hn"_uc%oagbuO0(*`aeg`%/y).`ͮʤm1R c&]_)+- 2@tܲ- IX417hd B7b%pX s`cp'F0sO ʟ-3bJ)k,.~ P4aa1oXpp qRU<V+F K M$pk8n 8jĐ6!4*bTEt|aOX H\Uaޣ7ysTW)7 kV\+$J5H]mX+s_8%V+@Ly#5׳-7&]OYkxc.E KHA`L44,`y;O4ѻ)"8g: U`0F="%oBqJ^ƶ,b U]AۛWX<'=o~0˄93T#[žr#c4A T[Εa 9X&$DauAK?ҠeSX Y_U\hyFHkFfࠦI[`p%3]:k,FjTYXj[aDy@pC>p,#rު9NŔ/>J}aaCYLtD; R@ꂂPY 0pP8 %,Xq'%B`LPp11qc4擩|LK$ IH-21aKIpO^Z"-GM2 ٌVL۴u'Z0#fdjgTh:V0 =؆7.U3B]/ݼ|!`0gJq @H@Mkꂈ 0@@\]~7CW2ZX=DAa;0[u_-31 ֡v &`~ |0.ӤPwJ:@#&@,%C;9ɼG#DD52O\Gj[,h,n=aj(YsIIM@cH{$X=Ry01Gy(LDnyO|r<‘}` 5̒SS_ ǛeuQ߂X08 !'+uc U OxwA9eO"x%cV_hhA1LAM6^at5DJ"GI`<0A[R5p'uW'n>% @%(_%gCMdi@p}RLrbZh 'M@En' b'V;"3i:4۬2E}hSGt 8+ U(՟nL&H>3vC!vT [4;:0`BŠX;GGaIEAh䰫1=:\ʁNRcms "FPXp09DU/7.p#:}r @=[p <㹍0-sŌp9n|ɰ.w(0+}/Tzr>L0!뫁ڷh.nl8`zxW@* V"#m|S| 'X)@DQ7Ek"S}N.V.;`zQ 8ʉN#Ġ{pP$(}鎓Ơ=J rQU}$ V7f,#\`@fse焷hwhsY%Hr".@P-82t`+$=5at2@uZɠ<Bę]ؐ`Gpڃ(N*PQX ɠZM:Qq j D ʐ F#0vRL*WR,UiZ'! ,<< dihGpl߮#D 0@dϡhШt@NH/L ;wmfKثU}Ê|A;%m4vm'Yqssuv4b  }MOjRp\Rb  iAPUo"[lP a~$W#[ςPQ4z чala|jbf:9k b~sb !P@h!pvv"љHYɏڈ9@(d$İP-:$],"X(*W"~:U-6X3?e]2tq< Zzʁruu@5q{u B,W~ȗe$̐8wv6U gR E"X@&s^`ˢi4h $p-hYKgIw+> @G+8,/X#\`&ȖuЁF -XIcģY *SE`VL []X0ܰμu܃Nlz[NN0HIM#Xk;sz :AO>'aa(L!{γ! ӒAmD0c\Ĕl5V}B1HŤGLZ6A TNHkH(@@`03J_8Bjq;fIZ̥.g)]%!Ib ! ,<< dih:xtm߷Ȥr\P֪Gpyt;YpސޖghjamT H[]%|:w&[//i:oXZxy`$gl Gw]L^c~"-{^oy%+m_{`ņtvffnqblUYw,cW,DLzK&P@{JC|f݀J{NF/]ܦн6n1E4pk9*Gb4lgaƑ3Ǎ!X=gF!84X{ӝJI`A]036O(PpհH1]s}% E1ˋt-A -ÈKtnhr騃LrӦm`H=}gNb WhF`Z7qM:Vc!>TGdb&aP3bd~h"5fyi 'OPAax*4Ol0 I'PzQݢGXf!vAfЀ=XȄ4@u%^-(nSi ]e'J4Fj.\VEzLjATpԥRf0fiBmGBUl;j6TS>s70gP{=poWP58Uŵ3G>_L|.I"6 @ɽ" vP̉l"SP!o೛$4_LY7ʓ[j`GF2̇N]U@$jh]@I?ÂR %QشTZ*Kv=P-H Ri ni:*;5d[oFH 12N3t$ؼҿ6 (:Y_v*2 -^ךNI_EΎV*QGDѹ)Fq X΅hYRi$,b0$A*p {?(6lyD 1d,Aq ay8Vx YI !C'jk_԰ %*5qNNj*B+{PBX8G/xAȀ+!Ht@ҶXg.tXG@"h1hX j)$&@]Bř"dАV %kx:̥.w^R 0KDDd! ,<< dihGpl߮#D 0@dϡhШt@NH/L ;wmfKثU}Ê|A;%m4vm'Yqssuv4b  }MOjRp\Rb  iAPUo"[lP a~$W#[ςPQ4z чala|jbf:9k b~sb !P@h!pJ;QFL$K,cGu "BtQLJ*.x> i 43?z0၄gbJby9T;GQ 7LU`& 4_J>z2j 2PȧhM5hΤA"uWFiM(~ Gwk Lr@RP w؜s3Uv{g2Zf8z%&A0w`{Ў=AtS4F<'|Nr=08:͖F(t&KwwPm|Eauăd̈2Xp&1W$OؙPE`S B5=]^,i_BX+MAHp[҂G^8ujxf~IWAFtJIwFPДL תALp)=#GYŗGl)_3A{?4yCI~= nVpC@?/P(to Z}1NCi5* )&DUT!)X'0g,OLfA19TP7օ[T4ELgjr!렵Z`[RLARꀘ80`2rc@[AExPm#(4hgD䦂*ܭT2`pA& 6k1kֵ2`En,8CX+;ëhXQ&=;z*<`M1~l):+~\p"  Z@ň跲HNLL&c,sWMS0Ch0]lc6>nF4w@ y/|~g1L X`Rye; 7CL#Ev C5ɍGƯ.L(7I;>Ok6Nz (7)Q%WV ! ,<< dihGpl߮#D 0@dHCўШ!@zbKWkU}iI\0Ө'Xikkm~t"uwNcQ&Zl}|mPnpcAOTg"Z}d}t4%V#Z{Oorrėoס&vLNЮ{{PRVD? <zۤ/@ {O)RLNX@HA$rBZčD#ϞĢ2د&|4l A&@CdiH|*PM瞍DfBDwT}ŠS]Pj|`a\j׾v= PДDjh&G FH#A"7M}哂g!X7YP-) 0G LKsZ@EtW.4zU XݜLDj%L g`WN|j-ls@0OmX`Eak ǚy` d> f0@E(` @Pq(RbADX GK!,p&)g:dPD"v\<`Ђ_4AlZe.dIT|4͚lPh $ykPbAziI'^dZM04f X U\@{Z'DB |J*YMCJUAt@*ʦB*lAB@Zô6*jhB[#C^n {r°4`lz7llSl&|K˫~6z2FK$r/"D\ 0@i2SY";ܠU)) 0imc 3 \d=WBCô$=(5fHQ JɓlDQzh[BJ_m8GtNT =>M?H@[atK$y*d{4ב^$\L} оUmH$ D?Aznr~T`}B1QТ%ջFGƮCV;٥90 Ib9 4XEz)d4| ؠnDQ E\D ./ _5v5'4\.$>ʎ(+Ge$:bӒtG]j,0h.IFR +p`"^4Gc>c*(D쟞1p XC*[[@A$ t@RL*WIJ򕰌e*HZ!! ,<< dihGpl߮#D 0@dHCўШ!@zbKWkU}iI\0Ө'Xikkm~t"uwNcQ&Zl}|mPnpcAOTg"Z}d}t4%V#Z{Oorrėoס&vLNЮ{{PRVD? <zۤ/@ {O)RLNX@HA$rBZčD#ϞĢ2د&|4l A&@CdiH|*PM瞍DfBDwT}ŠS]Pj|`a\j׾v= PДDjh&G FH#A"7M} X7YP-) 0G LKG "+mqHwZ4X 0~l3H]D <ԁ!b۩q ma[ ,@\@ d>5Y7kaqTGp|Y&MM5 %"~D<@ g_0d`%k (<s y}_LlZp%y4u<\a@LԟdA*('LB@=I^f*ZYe XqhHAH{ce)U fD("` ĚDVʦmj0?"PY HT$Z2R tzMl0HRmqޠ pj+8 ;xHxNy<ŬKKTp`W;FHZ=4 &sRPA`&Hl\ &^P%imC@ll31ĩׂYƴ sIC{!$g35f×!؜54G O,#J zQeCwՈ<ֵn@A}۵ҎXpr(H]KA~&jA7ߩ{qGy wxt9p&ީy 4بP5Pxe^ E?> x.A5'1>q=I {"G8IѠH78(P7TGA/bpqⶎȫrܮmx `$nY10 1GV1gPw#nC*{$?[^ +p^4<>TExdc/IwG=/}È*2r{D&IJZ$%ENzL(GI! ,<< dihGpl߮#D 0@dHCўШ!@zbKWkU}iI\0Ө'Xikkm~t"uwNcQ&Zl}|mPnpcAOTg"Z}d}t4%V#Z{Oorrėoס&vLNЮ{{PRVD? <zۤ/@ {O)RLNX@HA$rBZčD#ϞĢ2د&|4l A&@CdiH|*PM瞍DfBDwT}ŠS]Pj|`a\j׾v= PДDjh&G FH#A"7M} X7YP-) 0G LKG "+mqHwZʹ,/\D.QRpvE7Zl;UX`yHV]0 d?eM\C xkeA0@u6ŚdML`Ș@䘎kYp@y$R HրO50d ,Xȓ1W X eD9ee)g$pAP&pd3SgNA( 7lIId ( %ـe<%uf:ƊC1ndZʃZii! N0땙Z @ uJ!#=j0ϲH;RF?$AA"\K/A|y-C na^_T4†40alsH eA"U % ,H ~"$}P T`-"k$F- ȟPNkđ3ըp͡<F:򑐌$'IF̤&%Nz+! ,<< dihGpl߮#D 0@dHCўШ!@zbKWkU}iI\0Ө'Xikkm~t"uwNcQ&Zl}|mPnpcAOTg"Z}d}t4%V#Z{Oorrėoס&vLNЮ{{PRVD? <zۤ/@ {O)RLNX@HA$rBZčD#ϞĢ2د&|4l A&@CdiH|*PM瞍DfBDwT}ŠS]Pj|`a\j׾v= PДDjh&G FH#A"7M} X7YP-) 0G LKG "+mqHwZʹ,/\DhZrY:HAyChԃV $PVpvw0@~7@60% 0! (D10F`Dх", A;f@@VAP=`!k:>e%lP膁$.d)c)#Xj#rnP UPP3p~ЀS?f0Z6Z' ^{IJRdfYn XŠ@=9$eӀ(1 I (j!~P@jl":uJ!'PD緗b`opH[C_F7mq0@`Ry@\Hm qXE%1[UKj E|hBHp C$ J5RmsV17P0.VɃKU~F$0,\ܜ}lࡂ 5|<̲YpgR\@EJ,<M7Xwo+@"iCYv bG'Cb$>NnxHBv׺?){εJeؒ, =\^3~B4T0P$:{MsNC!~gٯqATWa~1؞Bo.;95a~(, \ .nebj,97 ^hxX!2^0+\Bc%Rܥ?\x"t0M'iV=d]Δ@M'ڢ*HЏ|p4 ĞWd5yBFf 6ԃ&Y5Zp@zD@<@#NMEi$a <s yade)'LPdJpA4u@<\a@@x~饜 ,kP(Ja @@_ڀe,iwFDIQI@d6pDC.#&PNR2 Zȧ ;8L.<@@Zbb IIz*(/ F;J/kPXTHR([~0,`@:h7]pF1dž k $_XQ fZFVlН0e|<ͅsHJI1ph Tט!Qwl9snʍPi[uV[H\0 FfWFs}\=L|YہR$ÃxlPmNoyvm^K$#>~ݏD^yCBc!t%C0!Ph DC,(nGl]GK?(o~|҃*kO n?-1ٶXc 8#HF]&6~F? % >r$} 1s0yZH*>0V29ɧiFĦ1qc8.4P ؇4!ynT:=!$F ,{zӝ }WC[6eX(GIRL(EV\,gI! ,<< dihGpl߮#D 0@dHCўШ!@zbKWkU}iI\0Ө'Xikkm~t"uwNcQ&Zl}|mPnpcAOTg"Z}d}t4%V#Z{Oorrėoס&vLNЮ{{PRVD? <zۤ/@ {O)RLNX@HA$rBZčD#ϞĢ2د&|4l A&@CdiH|*PM瞍DfBDwT}6MpgNuAi pMk0^5e`A $RC6,>jHH'7@seʖy(F˗Oj`7RgkT7GLG "Cm \k`b(~b@d&@ ,|v7D)^٧ f'Gwydcx\S$>ŠYs~W @Pu(R}}4Ix@ތTq4KaLA$(θRF` ɋ<s yaP-e\ndSJpAY#WP6.E\iYXsx0\֙f Oh=peSO{FDI9I 8`٩,`$%4'+7j(.;0hB첅@gDQGVKIo,lERJ1X{*=HJC#I$(t^/kcIx+kV,e$5 J67R`Z!,``X#+'\Ș0/nG ̜Ssj=fϦ1skY JJC1BEbC w ѻcDpvԏD ijn:y8 q=PEU n8T[g9~LP&BӳGKv QQo4ROX#WQ.!YԋLמi DC, !M{1LY?mr[mZo-+\! 5P.1S,47΁Ya05R-4 7e!?5ü%aPԧcB,RÅz9-. SP hHCKыPV&_QD0>@iHMzC/A@Y65nD0\d%8򑐌$'IJ:R̤&79x\A! ,<< dihGpl߮#D 0@dHCўШ!@zbKWkU}iI\0Ө'Xikkm~t"uwNcQ&Zl}|mPnpcAOTg"Z}d}t4%V#Z{Oorrėoס&vLNЮ{{PRVD? <zۤ/@ {O)RLNX@HA$rBZčD#ϞĢ2د&|4l` L^*8ɂ Ґ LAՂAAer QO=lYhFa RV`L6 ,$Q \a빠_hf'A[]X|Pgw$H; .x \lh0!1r?@=sf2z, 7/>C]F-ls 7~7y07@6<%Nq>_4_(gDш","DLCaWA= ",A Lb_솁$d)AFe b+TPP;phSuj@/rUPz@[p2g6Xhb rYOFD]I0 ѩo  JrmEX ((DAE HV!Ւ*S! f)ԧkRo$YBP j9յeH2x{pUqiNkcI$aUQ%j@,}񷁒VY- |#uL"8tuV@Y Q |Gk{6c!Lbs0x5L.Qa,nz. QHmҏD t]ܪrtHoPE4zL:CIegq3 ٛ˅BxEXK>MBKROXC!X mZO:iAQ 0\؃=-nO,]1?XLOhyC%KmxA!5@~5X4!7łZ 5/ X~A'l FFPcC0d< Q{Iĕ$o2 km_Y ~րi3@&µj1@< p;)Y6  uF<$'^i3m %蔍(wy2X&7Nzd0JM L*SV+! ,<< dihGpl߮#D 0@dHCўШ!@zbKWkU}iI\0Ө'Xikkm~t"uwNcQ&Zl}|mPnpcAOTg"Z}d}t4%V#Z{Oorrėoס&vLNЮ{{PRVD? <zۤ/@ {O)RLNX@ Au4 Γ h7f[$` 1 J, ,*mG N;y$ dV!!UQDfBD}Ɩ4s  pMkp^ڕ\@y 4e IJA~JvyN euM^Ȗ ]geLDk< @`m 0 ^A6C! <] dA"G@d P3&DOsYQ%O5$ Hr׍gӮ}BXB՝:,EO !D6.7:5o $==P Bk;Z=pYU;QApqBT#aOqP5[0ؐ{q쌇=0؅ P̋QN%AUaĶ@r ecYbOcXh 6aUxhwDw✑b15q RC%x (G9|ҔHV\,g9KV ! ,<< dihGpl߮#D 0@dHCўШ!@zbKWkU}iI\0Ө'Xikkm~t"uwNcQ&Zl}|mPnpcAOTg"Z}d}t4%V#Z{Oorrėoס&vLNЮ{{PRVD>@x,n@I_ DD'|Mpb&bl 0X@,<P1)qcfyE*pQĢ:د&|4l % Up[#$!0-֬ @FAMnoDtOq>`n(PA*u|`a_j׾vEfm8n 3=9FF  &8`cA͚O`:03v|:8մ 1l &l-7!C~?@?sČDD] 0x_GA ۜ@+>L`}7&}T^7|r vT?G}G~_W20uEh_zPXPPT$`:-e@SJ&DTXЇ !HaA ωi\`%b\P5'WP6#(A[`YPp]֧`oF } Tb硇DYIF*7jX-~OTP2b L' 7pЛh"S!1z`~;R\[jt#OϾ%ZUyȋ"PO`ޕ\1"6m\`4]u/wI(^JIO-61 F=[, w44#0q6J&)OʯҨ1Fy&EG}Uى&@B^j?;PT[[œe@C"݃eF#j|謒SPm1r$xZn%̀AofOۑq@͟U9I'B|MO2P r hۃ H@9Z1<52QWSZZve^@uT $f U`cB窇=#A/!U;4]I*0ЃPWxQ?M"x a0|yPްA*h/n Aj( Uxњ>b -˟D8"EٙJ4(H pMum4P)=Z* 7hG,xfIZ򖸼e^Җ"ȥ0IbrL2W! ,<< dihGpl߮#D 0@dHCўШ!@zbKWkU}iI\0Ө'Xikkm~t"uwNcQ&Zl}|mPnpcAOTg"Z}d}t4%V#Z{Oorrėoס&vLNЮ={PRVD? @&} (0 DxO)R%dNXL,P" 4hgE^@˔1<"74 Jد&|4 m1TР $ 1?XSBh 6m48 3°|ݺ #;s.|`aBaj'i׾vOƔ5 jϱ,H#AR#@d`fiw~wkΒ 2P`@@ t{14ar&d09 nN."'63)T A ۜ@+BE>TrQHO!D\c  j"e )mER4OqJ[e@QЄ᥸4cA Y7V$p @b9MAtHSƜ"cA Ŝ@]tIpA w@Ix\a@ `' u&Z`jXv4@\ěcĔ@ZDrcGr~1X* `[$(Krp P<@nmOn1ѱ*YR@]sKl8» QE.F?nXKTiJԥ@Ai⃹a$'ǔ+R1y؉n! \N4KƔI=d efoӽg|iBPXƓy ܵLUN4=M$%)tu2 ל!FT[# s(X= 8wH K6:=7,0=ĸK;G,@Z4#%nT{Xh`SaB'{a@Tx`@G{%>IUV'~Xb c:v EDa6C5cs_+)PAbvO}x@0H`C 4"?4F h6.BZƍe6m0 pE`M* \qA{|[L T7*+d:aMatX>iI.bhjp.l|`aak , *wuIPG%>2X5kf vCcS N #Bߏ7@7'@ [R14mAX t8=1`9A@\juQ: u16NDzŁ po\W<=6l'y`\_]{(WBFhctQQZpE<@@6`^:QE xuH%TƜ"ț |s(ҀC iCEUt~10<0@>ЬQQd%=5pR̗i]:R*`5Py!yOAGa??rTh5:wJHX$'xFiBan^7|:R2ael|F@qTqסv@ %&t%w70Rhw_ذ;?ESvɽNiPy/HY:ŒA"|E V*d'O~5H,G.\/B1N5yAD ",BX-,04J^ 0# L^L2f:+! ,<< dihGpl߮#D 0@dHCўШ!@zbKWkU}iI\0Ө'Xikkm~t"uwNcQ&Zl}|mPnpcAOTg"Z}d}t4%V#Z{4orrėo~&vLNѮ {PְRVD? X`C qV (6 ; l%_>j=>' ~l[†34ũj!i7f\\ ƒ e) 6qh  ޵40!Au94g6T@p(8P%'@er.TO=(7.\v0aC. bak 8Y?&@+׾p9*$X#j>2+,Ao 9M{ۍ`  18-R_m@\e6@S(&ewahF y_Ul`9A[#jtn Iv0]4N5X@ s=5@(hL r "=F `A\Gd(Xu>`xzO(e|8 PZpE:2@iJDq 3ʚZ2. 4 Z@F,'\x3/:ݔY%"7Hu}]mq_QC}`DYhc0к@0n7RrA TPWB>P¶"a=L0B6L1:cA2 ql*Q+LߜB$={ultK %!`QL5{Pdx/.`zv-1ʡSo-p-  Nrt0Ёm>XXyvuޤjQͨ.-0`3@bXlbSlQj yxуfGC41 ܧ/l`1nւ)8I% aLE2\eBY踔54+y( @dT4dpzC7+A ob T㒨0L`vZ̥.wZ 0ub+! ,<< dihGpl߮#D 0@dHCўШ!@zbKWkU}iI\0Ө'Xikkm~t"uwNcQ&Zl}|mPnpcAOTg"Z}d}t4%V#Z{Oorrė{_~&vLNҮ RȪRVD?Ah@O^ Kdߦ~+P  NC(a%#' ~lP\Ył7LEEaHZʍJ׉x 'Zdž-$@,XeIeӜvs%*Pp%6460! i7LMM=@Aq _q0D,i-ֹZ3@ A0 ک,O EWw]\igBvA $ktqm7D&ph@{ 3`+xmb@9[a: 4\udžH8` IxE!6cip' p P@ r |"=6cGHWb:uж 7Pd4! i0 @AY1OD@W8 5AsHr$qȃ aP4c'FAdh&c\P5R'WPA[ h 'Лk&!]ap5@i4! !+)EۘZJq@t`%%$>E 6JRH@knldKIs ,`)TqKĄ" 2V` D=$Aq|h"X* qxV]2}R1@#cs2PN%sJ E޻#I@ 6 PKmm`FQ7O'>@aV\UQb]QB9w_02mAPZu7x~,Z}5ȸ`e}ՌwDmMЕmy404-q|HNhSKmP`F1$QĢma d-JSqFrPD@lT\YP4e@aJ.R6Tחz!Pq 0'-cF1an;k\/m^@HQD;梉0ӃdBXT a|@8E,Ý//\G gXlAlHbh D1| 9)wh`gXPxC.Go2)7uF8 'AN@\PZ,DaYʝ{Ӧ$˜T`x [gF G3f@4(`91\W (r]|PA pl8dx`헁D\ A) i# B5_H!`w8vgL*Y&}XpV$KE 9QdhT!`h i#AeA51LpApu@x\a@wa@^l(9B#Z`qr~`w @\k8U0#)EJ\hZLp f XP2@bj*9Gq[hTDR$14p.g}*.nQJR2Ӽ'ϜXQE\TJlqĽBF* !.5f1$2- ܨة=0 "}L]dsqnRgsOx9-qđ3*0^mWѣ4L:it,`SnHA@ -Ҹ X"Ks0 1DֆbYF P8Kv1ZSEGx{61unOyn2jKj J"0zDqf{w0PrDc&]1w2o\EIM3)*1 b jvcN&: CCU%팸c¬^k%x_z>u2 DWFxJ6 k`.a^z HS6p0qФ,*8ADn'>@:b*$OG!О5=jČ> R{zӘ%!\Ba U>0(=Kȥ.w^̥IbӗL2y! ,<< dihGpl߮#D 0@dHCўШ!@zbKWkU}iI\0Ө'Xikkm~t"uwNcQ&Zl}|mPnpcAOTg"Z}d}t4%V#Z{Oorrėoס&vLNЮ{}^ևRVD?A@kB 4Ъ M<8W'NaC Ġ􃥊`= PyX+`A rFC=qcfYEEt"XA ?fpdJN ¢tZnNWڐB0MQ'ynEtY>QYңB@ #Μ:6%ni 2x S s:%25, 3 l&`RO@56,\;W܆2rt;bzio܅E JY'H'g,9Z|#WEQ(&&mvtHewLg@Ss9@I Aq =sMTt0CR{rcW g!QvZ*.QY5MW$XS(j]v$)Ux@BdONKXT@WT J pl\PP0TP @'1uw!@ @tA!.hs1\xNjE, ~0AzH1J j!-98XIh*,Z%[p&2VmFz l@n BI22wE?-@ aBqbf⇭42(2@E ˥‹y5!&OAr(ONP8<H0@>GhU!/;SrEnZvn7_@ >1 5e5*Ǐ 7cQ(02lHP.}E=ZKrAXc"POm#o(a.2 MxP&"hFBruBb}8%=JmH/W3`wڛ{#bw0*NOh\ a>C8B1AFL\d@HР:^xέ4Ē$&="@D:G,ᖸ̥.w^"0IL^L B! ,<< dihGpl߮#D 0@dHCўШ!ՇV.wnW0]VlL Z@EiiZ[{q"tNRfjO{|qsLNAzV$h{lQqZv$a4"hOborտz4ט&aDQOb̔X@L hOl"(Iy e`B2 F\Ȳ0+PA #0 (0%Zقe|(]„ F_\QA s4lJ@%yPK ضePԲ9!/c{o^7@i&@ A> Z@q@ \&iL9-[[;dhv=zzfjX6q^fT."WOy&-hE1ŗ{$EPug^xG-z5=qfh_L^6ҵR t-5φ|7I@PIXpO4%`Xj XTUTNg I@4\at-}e} Pe+αUY6S pFe@{nEHh%\'}]F/@|F}$%J% +i. mc0^ ~O4>nNҎ| a` c5c>Eb8"Z pJ bfv <u'XLUy9-! ² "2Oē 0<NJI CpA8@.f+1M4c`Y/D,]Xl'I&Qz"$V;g4|BQR~3xE{!Hݐ8 ̥.w^"0Ia?L2! ,<< dihp,AxN8@X-p  <l:χ@0MXv[lT^`d=ﲴ|0)j0Yxn"]_PdgMxynpJ2wT$}xiOnXs$KL"}M`loҼwLԕ&q_VQP`ɑC1ҒW(Pa@0⽃dU:$r>taPT_Ф>[%DD󇠧Ϟl0aå40A(h:]0h!W Qi TNΑ&07E~ɭJ4zM7pI˷,=@)S,tgk܅V㟣OiD~ V 4pqЊu0H*В1"F̮aIM0}K굣 ! h:p `LQD=j `[!mxB'ȯ@UdI W_SwXNgӊ!Jl H ӒEOqu|S<{iTF30Dc8~+Oxp~LX2zCАO462IRҒ H@ Bh&YɣSEM vh%,_I3@[xEc6<7Pt0 8Ir~SĦ:iv]Ph,A! ,<< dihGpl߮#D 0@dHCўШ!ՇV.wnW0]VlL Z@EiiZ[{q"tNRfjO{|qsLNAzV$h{lQqZv$a4"hOborտz4ט&aDQOb̔X@L 8v  AOޤ<r/B s{@@ 2 ~ bVʦ-Lϟ>BrPl ֹ d '  P֥M r(U#˚)Q-Qm}aÄ ԀXx> P ~ܣp[E,lWEFP2vχtX,@|navO.&8+ m/81+(8дګ "5dpge|.]vX4 r76Ro4O;P᧟h1=(`T{"4g9dS 5`e& P!0@@;2gel2 T`ZaәlW \r@HTALCvҹPfZ  h(v/|5j&)d#QHa䦒͑%<:enXE~ʅVFP&Qz,p<5ҪGQ\XAA`m<fD;FR-'?BK YX QւIpR[YX.6oF -[Se (,)f[Z$4aCt{ُ5<)Q 0Mf\l*z(Y=s1@ lg#1t$)56J[XƂn/>qW'=F4kIEVΏ ظ8Xfqm}SS%aou/lY5;+x=QUl&!MѰ=#B!L:]f3LjibfWgȊl 5^$ @Į?E,`Y+L+Wc&EM0{`/Ч(%܃Y4 \5_Pػ=Ƅ,8g ]03*M<qX,ū$Y |Q /JP1&X"4q|*wVg8y`!D^Kϰ،H*1H!"ׁzD4"ABԉ[S=8t -4D"ߗNjy^†8Q0pZ 򕰌,gIY̥.sy &B! ,<< dihGpl߮#D 0@dHCўШ!ՇV.wnW0]VlL Z@EiiZ[{q"tNRfjO{|qsLNAzV$h{lQqZv$a4"hOborտz4ט&aDQOb̔X@L 8v  AOޤ<r/B s{@@ 2 ~ bVʦ-Lϟ>BrPl ֹzLQ`8OK  ܸVRB}F=SZzk&b7$H`⿶1oĝz]̈́ 3lKH=`4&DjM<ΑD{!Æر9C='=fez5QtZQVɧփ]Qu#-xir=X6Rn4Or``L iDHVހ |@w䱢-Z",A5clR^H8I_G`Pf @%XRL$!m0a]dDd ,`%lh&ZTZJqYf SY@g_qPDtUd#TNzpRƮ GkʹIr c`if-i9 klJm  |l2mD#o:*/Ve2m_e-`N0I.)2e7zA1!(ݛ/d 3G8JI[1LLk"SQ=)$IV4Hy}ڀF;W77]^S+_Rqej,@kLp eIO9sM~+A@,=j@95FAO04fT_7QHsؙBfF= hyX_ TE[:@LъEÂ55U t+:MNb8¿VlVTQ u jx @(XOy BY&ahS p~YQ~ްI`8[ꬣoP8}Bg [&J0VfN\DdF4,#h>-`a5jB>>:2h `708 th6Nz (7)Q%WV ! ,<< dihGpl߮#D 0@dHCўШ!ՇV.wnW0]VlL Z@EiiZ[{q"tNRfjO{|qsLNAzV$h{lQqZv$a4"hOborտz4ט&aDQOb̔X@L 8v  AOޤ<r/B s{@@ 2 ~ bVʦ-Lϟ>BrPl ֹzLQ`8OK  ܸVRB}F=SZz%.5ju g $X0_ۯ"<ᯒ;軒1ɒ,X8 X-A"FӏHW yy#3202YZFqi[G`Nvm|.Uv(Yr@ex '6߁Uo4O['L@(jr=Xp^P0<0BrPl ֹzLQ`8OK  ܸVRB}F=SZz%.5ju g $X0_ۯ"<ᯒ;軒1ɒ,X8 X0{/OE#{Ǿ $w+l(}8/nHb"Ὂ+#mz IYE^M`5`br`WX5I+A0AIe[+O N+Kd`$8AOP`qR0p@=hT l=fdI`<@5j @UfWDHuA%& d $@tZaj`T`@v@j%?jD顛(RA}*fZۛ%&TDXkB *kjrΙp2B@EYۭj4YlP;0Ve k@y;BQYǽyfd ܬLƄ-6H~p"Sn|\ 0 MdR;"kȧh,V@hD&גg\B) !tQuf)T`PֿtwxҶrNK˼4.DqCPXCM@fc7s , MYFv=z" Fw ņ0yT]FA/ Ta}Yk$ @"yt@FBqԏeOT`/Q 5HS3Gx၇TX%dF$|яZb&IF+`? r*L]E]Ѧ#V)j7ʢb(ق6ʑ0,D (;Af/mh*PٚU\eea"2Bi+Q#h:2|hD5QKE`1G|Vc814k&IJZ̤&')MzdGIR ! ,<< dihGpl߮#D 0@dHCўШ!ՇV.wnW0]VlL Z@EiiZ[{q"tNRfjO{|qsLNAzV$h{lQqZv$a4"hOborտz4ט&aDQOb̔X@L 8v  AOޤ<r/B s{@@ 2 ~ bVʦ-Lϟ>BrPl ֹzLQ`8OK  ܸVRB}F=SZz%.5ju g $X0_ۯ"<ᯒ;軒1ɒ,X8 X0{/OE#{Ǿ $w+l(}8/nHb"Ὂ+#mz IYE^M`cl@j9z+~dMliEf\P_xJ-5e]lCeʆgXuTz-_, QL1:Al"ZE",d ,@dEN"PA5LTRYTSO`pd ff"UYvA($|J79JH@j?T dh2P@U:08u!.*Yd#ܞ閦UZ(:т٨ Zjdf. A`na%a iۯRi|`;A(@LM'GK4۷5JE:lʻPg#cKnBH&7g. 00n+GY^1!G Jt1IA?$Q0ZW{t-s&ExmQVf]Ah9[5Թ JV7s]B`j%Es`lԗ5uCLJL.Kn){t\>1r7=!W!k$PWll mYrQ TC$:̷!)B\\lAFO= D=[g L|rE/0{bU0Z<ٜ^#:A 6pH7.0~#7ذQ{&=T2P?z㼚„AZ:!!()ҟh``0ֺAL'H | H홑ڣID(VE7FJ 41{] 񆃩ۏ@BL"IH0򑐌d"HJZ!! ,<< dihGpl߮#D 0@dHCўШ!ՇV.wnW0]VlL Z@EiiZ[{q"tNRfjO{|qsLNAzV$h{lQqZv$a4"hOborտz4ט&aDQOb̔X@L 8v  AOޤ<r/B s{@@ 2 ~ bVʦ-Lϟ>BrPl ֹzLQ`8OK  ܸVRB}F=SZz%.5ju g $X0_ۯ"<ᯒ;軒1ɒ,X8 X0{/OE#{Ǿ $w+l(}8/nHS-Ὂ+#mz IYENV`cl@j9z+ ,kqA^6Rnd5]|taPPDXu#.  uE?6HOaL(I,#jD)`S$AEa50YXD"_f $0iil\r`biHun@bjiUj`Ph/Yf:*L@bKf*I&G8)YJkhfY%{TED-8+JM;`BDLjҬ@<<0l+RINtTܨ 'j ND:QJG'+rmITqqd B|4 RǁOl q;T&Ւ7:G7ax ~HѪ`wO ^dž+<=Ž`hDnYGqs֣tIem~ tWU#K{'!$k$Z Tr\vY/Pa}H(1._?M,|h̍ ٣@= D9_aʽ~/CwZǎ>V,& IZezqkЋr8WejF|@AQHbkXoE'|Q2`n}4.P;Zpf(a ܯ.o "1+X>Q٣({bZĀIt `G|%5 썋4!Xq}۞ 0/~Qp ABL"B$JZ'! ,<< dihGpl߮#D 0@dHCўШ!ՇV.wnW0]VlL Z@EiiZ[{q"tNRfjO{|qsLNAzV$h{lQqZv$a4"hOborտz4ט&aDQOb̔X@L 8v  AOޤ<r/B s{@@ 2 ~ bVʦ-Lϟ>BrPl ֹzLQ`8OK  ܸVRB}F=SZz%.5ju g $X0_ۯ"<ᯒ;軒d ,X8 X0{/OE#{d #(寰|L< 8+u\ahcNz,:0yzٞNY(@ZN>[-{t| .h0k80A 7x47 M1_qSQo0Y00pMKp8~,ET`OY7@ka^]'G71 '*mE3H4LKhϱŊ=l1Ӊ[gzNA.@kXD^P08X/0P]mlXy ~S 0 D{6LU]Hy;-_y{;A$G1.vX+q4T`xO/N=#@۳}7k4EK <=L285Zj~)aeAgU6$NV *(NTL<*L<6$msr/JbBh"\?\ߠ=\b0V,BDLsEOG>jH!"UB؛ߨ% y·ǐt GKH"F:L"IJZґ\̤&7y! ,<< dihGpl߮#D 0@dHCht|z0 /0emWmL! =ckkV(mpqq\]y"|NTX%s\R\y{LN#pQjUSyzfccQpde4_QwƱ"hhQאP&L̳н̨Cc`J:5h ԥeuQ H1'㭊0˃n X##4C *PHs寝Sɸ#dzCF]ؐC b p 48S̏|>3aۂ+Ed*@Lj4С0Ni;F郼zkTgG.3Mb$<:O0*&L43y , >͠\^ǏI9hn"X76p*w)e~KQ\ HpNw;H #۩F6Ђu׽^WkUgAт9 LxځuX/GE.\ ~1 hgZ4.[' tz9z] x3xS"aƉ&9"t _醤.@`PA~I&$< z6rad0Ae P@9-N|̜@dAD* V(T' FIv@髕!d\Hn)ybMf%º'5X`hpqr# ymV phB=b,b)mW- fou&gUb`n x'n̿ pR@‘<JMgϡ2gS͍'oqbZ0\`] k h@>K@ö;d1!J#1`\sţ wcb>K$1-AUǯ '"C J=5 e6kq 61F|,wtˉ <-x.DȂ;`ID*HIdPv]ؑEe:OőxdTLڀq74x;rg^ETK<ϴ@V eftGISrzD~``L,e{gr@ ġ^/[g9039%>S4$|Rfלds"^P: ,9N2(  B>nN>V(ʸU\0e.Q'Ve/)mRA[? >GgkfŸT)y>NLT[$95KȤ&7Nz̤BIRғlL*Wy! ,<< dihGpl߮#D 0@dHCȀFZq}x0u#= l6H&w @n! T4^(nqrr^_lz"}N VZ%tllz|LNNl#qSkVz^=qjTkSޱg 4"QQPوOl&LfD@ .ʙe uk tFP ?M!v%u$@ȇ AHXG@`UyKB- ciYAӉ'@ @ȯjGyTpQr*}@@AB.χRDy&(ۘ&W!HoTjVԡ0A), ׾OyZ`>y2[iO 2['-ny\:5*Wh\6`BPZ{N̽ L6 1B _tA*|!-pn2^z%^<ڵ|Ty:V2X 02͍V @(|P3 t C$J#~83xk 2,e#䣎@`6 5`PAQU288ޅŠBp\F{򴄀)0N*IhH=AX8 Z4~%IohkÇ$se Eµih/lPZTrqebEdC0VO=T _M--?X""/VЀl;՞Cqjg3]݁ r$]U@qV.k4㇟/4 =QwaR_ni&CM쓈G0QgEYp!yTD4~a$g&+_T  dh0 )RXp瀀 E= 2YbUND8B xÞm< adB:gfl24T@LzDIxmfh@\`cFV lDcF#[cm% /F ˆ r' $ Vlb ̤&7Nz(GIRvL*O! ,<< dihGpl߮#D 0@dHC >d@Z>װp&n@iI^0g S4_(pstt_`|" W[%vX|~L< U#sTwXW|_g оsUwTRRi݊4X&g ukWZhJ@VF!hW@=Kj;:4/V0 Bl&:`Ay-J`gғ]^M`ͮ (.PH*y]6 msA"bBَ7MDG5p#8G'Sg♻Cc}@D"QvҳSɫfy@t,P;Uq@fk,P r^@QĤH1HC/ gf 4@`TG rEA\V=(V1d7gHjHQLiZGA T]@X`n; @t&L(,nFe(68YlB_,t}! \kܵTpghԱӾUXt]t=A4Q6LU%wu_v2TWD\@v%T`CM i)x :gEDr@TOP" a<#{OD1Ny6nqA1!4E@pd?:_ioHwDFZrwaȲ R};Q80*}zѐX lu~%2auz4Eid<9Q( x2WzRJN i TPA5PV 0P<$O [ g3#$^!e3$j6!kL8mcʣC~j32W#&6g0#QNuυ/_6(6|;qt LT9B,2 sC('qBX* j[-,4FERQD?@^@\P& "qPIo|"|'yA6(6R#\$8$EyaQ@)%򕰌,gIZR̥.w9A-RZ?0`2kA=4`]h >91 t}gΣMwI?s.0g2WuԾ:uB  u 6/Xx<4`!_@lq<旿Dh C=4`g-#mFո=# x mH1Ѹ (TD*t?'#@DP; -uB ӡ/iKa2qP9@E4hK$iDŽǷfx H@Zw,YK;YEfxSILjP$s%H L,@Z̥.wIK f. Ib!! ,<< diBzyp,2mBpH,Iql:  hZX#zxެxcoຽtU2K\U[+mn`qw"xzTgXlppZsgFV[k#mhZwU%m~UruuĚkgr؊&yRTѮ ~Y߁ZYX`@@Ѓt A@0ABJ@@Ɨ.;z5AhP3z xˁ3gnC4X bҀx$hLRj` M(؆4G_fPg7.Qiq">[ba_j7ixL PF Z`}Ҳ::v:_ 8/YJ^ !ʀ"2h+ĻK@uû_@>}T8%BwzkQZpy Eɹt/ps"`SX-Qdg ! TBv{EE}X`wLaDHS==%h!t~AD# de4Nv_aPI !p)A|TLpAV9P6mSD&{L=WZ`]aؚlVGh2՞AJ!]rGPFi7 @d%ygK^2@A de/*G4p D)V.J$-Bb׎<vqQ!EB7ppΜn1T@/SE.bAy">:7˰J_Q.%GmFg(2"/@wK+&]}gA.]12wDw,|W8 r[ȸJ̲DY w6=\ J_+7w0 a"<T\rbJZ21ׄk2o3D]LZ5ؑ>c(2P@a4fuW`F<'%RL,UbD_E,4 }2ӈw&_ XAMcU VfZ4  p kxܨ?`Yq4t?VLmމ!' roC[g81op ha 6Q@JV(OdbM=W*F5TrZdStS3iG;x?u(14%)r{GRPJEv(UHDZҁsd':NBFIRL*G)UDgIZ1! ,<< di@d)axH(+al:aP0 Ьց( x<~B!p87IͱQ~gv`s^u%.o&)*f*hn"_uc%oagbuO0(*`aeg`%/y),vpʤm1=Rnq&]_)+- h xdnk&$՘K@ (`0qE, Txlp|R|jN\Rne0tWm@6t^PN|Rr`"~4̤=lh@RdڈiDS!C9EI ~9ЀwմhUy 9Yn*r„LBun!B$'.i@sL@saq Y >  w{dWYZ@Fhɻ)'rvK@t"X /H-%_@ME Ga8.ASa^weR0[ALx.pZ^JO\fԈbWXX6 , XZM%f5T8Cbv^%/Cs#q8aP*~ ap n SATPN.E@c@" TQ@Z`Tn*ᘜsip"Zd/IlJj* fF`) kd4괪2`zk ,SQal -I{s ,PB~NTLA(N +T<0Aꀈ0wu`Hb]P;7懭'>+RW:d;o2~ 1QFx/eَX\+{3;? Oʇ5}ibA'? y|~|@4 Oڐ /.?ZxOQ j6GVh=kjFDKbPU7Q})/^X|Gc:^ǂp<( ($X\(D$^n@ 0TT2I?9P+HDEVA*/Q&ĉ VV򕰌,W)Y򖸄w^1;optipng-0.7.7/src/gifread/img/index.txt000066400000000000000000000000611343170417500200230ustar00rootroot00000000000000compass.gif: The historical "about:jwz" compass. optipng-0.7.7/src/gifread/test/000077500000000000000000000000001343170417500163615ustar00rootroot00000000000000optipng-0.7.7/src/gifread/test/gifdump.c000066400000000000000000000054751343170417500201730ustar00rootroot00000000000000/* * gifdump.c * * Copyright (C) 2003-2017 Cosmin Truta. * This software is distributed under the same licensing and warranty terms * as gifread.c. */ #include "gifread.h" #include /* * Dumps the structure of a GIF image file. */ int GIFDump(const char *filename) { int result; FILE *stream; struct GIFScreen screen; struct GIFImage image; struct GIFExtension ext; struct GIFGraphicCtlExt graphicExt; int loop; stream = fopen(filename, "rb"); if (stream == NULL) { fprintf(stderr, "Error: Can't open %s\n", filename); return -1; } result = 0; printf("File: %s\n", filename); GIFReadScreen(&screen, stream); printf("Screen: %u x %u\n", screen.Width, screen.Height); if (screen.GlobalColorFlag) printf(" Global colors: %u\n", screen.GlobalNumColors); if (screen.PixelAspectRatio != 0) printf(" Pixel aspect ratio = %u\n", screen.PixelAspectRatio); GIFInitImage(&image, &screen, NULL); GIFInitExtension(&ext, &screen, 256); loop = 1; while (loop) { switch (GIFReadNextBlock(&image, &ext, stream)) { case GIF_TERMINATOR: loop = 0; break; case GIF_IMAGE: ++result; printf("Image: %u x %u @ (%u, %u)\n", image.Width, image.Height, image.LeftPos, image.TopPos); if (image.LocalColorFlag) printf(" Local colors: %u\n", image.LocalNumColors); printf(" Interlaced: %s\n", image.InterlaceFlag ? "YES" : "NO"); break; case GIF_EXTENSION: if (ext.Label == GIF_GRAPHICCTL) { GIFGetGraphicCtl(&graphicExt, &ext); printf("Graphic Control Extension: 0x%02X\n", ext.Label); printf(" Disposal method: %u\n", graphicExt.DisposalMethod); printf(" User input flag: %u\n", graphicExt.InputFlag); printf(" Delay time : %u\n", graphicExt.DelayTime); if (graphicExt.TransparentFlag) printf(" Transparent : %u\n", graphicExt.Transparent); } else printf("Extension: 0x%02X\n", ext.Label); break; default: result = -1; fprintf(stderr, "Error: Unexpected data in %s\n", filename); loop = 0; } } fclose(stream); if (result == 0) fprintf(stderr, "Error: No image in %s\n", filename); return result; } /* * main */ int main(int argc, char *argv[]) { int result; int i; if (argc <= 1) { printf("Usage: gifdump [...]\n"); return 0; } result = 0; for (i = 1; i < argc; ++i) { if (GIFDump(argv[i]) <= 0) result = 1; } return result; } optipng-0.7.7/src/minitiff/000077500000000000000000000000001343170417500156065ustar00rootroot00000000000000optipng-0.7.7/src/minitiff/Makefile.in000066400000000000000000000020261343170417500176530ustar00rootroot00000000000000.PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = @CC@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ LD = @LD@ LDFLAGS = @LDFLAGS@ AR = @AR@ ARFLAGS = @ARFLAGS@ RANLIB = @RANLIB@ LIBS = @LIBS@ RM_F = @RM_F@ MINITIFF_LIB = libminitiff.a MINITIFF_OBJS = tiffread.o tiffutil.o #tiffwrite.o TIFF2PNM = test/tiff2pnm$(EXEEXT) TIFF2PNM_OBJS = test/tiff2pnm.o all: $(MINITIFF_LIB) $(TIFF2PNM) test: $(TIFF2PNM) # TODO: run $(TIFF2PNM) check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< $(MINITIFF_LIB): $(MINITIFF_OBJS) $(AR) $(ARFLAGS) $@ $(MINITIFF_OBJS) $(RANLIB) $@ $(TIFF2PNM): $(TIFF2PNM_OBJS) $(MINITIFF_LIB) $(LD) $(LDFLAGS) -o $@ $(TIFF2PNM_OBJS) $(MINITIFF_LIB) $(LIBS) tiffread.o: tiffread.c minitiff.h tiffutil.o: tiffutil.c minitiff.h #tiffwrite.o: tiffwrite.c test/tiff2pnm.o: test/tiff2pnm.c minitiff.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o $@ $*.c clean: -$(RM_F) $(MINITIFF_LIB) $(MINITIFF_OBJS) -$(RM_F) $(TIFF2PNM) $(TIFF2PNM_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/minitiff/README.optipng.txt000066400000000000000000000002051343170417500207600ustar00rootroot00000000000000Name: minitiff Summary: Minimal I/O interface to the Tagged Image File Format (TIFF) Author: Cosmin Truta Version: 0.2 License: zlib optipng-0.7.7/src/minitiff/build/000077500000000000000000000000001343170417500167055ustar00rootroot00000000000000optipng-0.7.7/src/minitiff/build/bcc32.mk000066400000000000000000000022011343170417500201250ustar00rootroot00000000000000# bcc32.mk # Generated from Makefile.in # Preconfigured for Borland C++ # # Usage: make -f build\bcc32.mk CC = bcc32 CFLAGS = -O2 -d -k- -w CPP = #cpp32 -P- CPPFLAGS = LD = $(CC) LDFLAGS = $(CFLAGS) AR = tlib ARFLAGS = /C LIBS = #noeh32.lib RM_F = del /q MINITIFF_LIB = minitiff.lib MINITIFF_OBJS = tiffread.obj tiffutil.obj #tiffwrite.obj MINITIFF_LIBOBJS = +tiffread.obj +tiffutil.obj #+tiffwrite.obj TIFF2PNM = test\tiff2pnm.exe TIFF2PNM_OBJS = test\tiff2pnm.obj TIFF2PNM_LIBOBJS = test\+tiff2pnm.obj all: $(MINITIFF_LIB) $(TIFF2PNM) test: $(TIFF2PNM) # TODO: run $(TIFF2PNM) check: test .c.obj: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o$@ $< $(MINITIFF_LIB): $(MINITIFF_OBJS) $(AR) $(ARFLAGS) $@ $(MINITIFF_LIBOBJS) $(TIFF2PNM): $(TIFF2PNM_OBJS) $(MINITIFF_LIB) $(LD) $(LDFLAGS) -e$@ $(TIFF2PNM_OBJS) $(MINITIFF_LIB) $(LIBS) tiffread.obj: tiffread.c minitiff.h tiffutil.obj: tiffutil.c minitiff.h #tiffwrite.obj: tiffwrite.c test\tiff2pnm.obj: test\tiff2pnm.c minitiff.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o$@ $*.c clean: -$(RM_F) $(MINITIFF_LIB) $(MINITIFF_OBJS) -$(RM_F) $(TIFF2PNM) $(TIFF2PNM_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/minitiff/build/clang.mk000066400000000000000000000021451343170417500203240ustar00rootroot00000000000000# clang.mk # Generated from Makefile.in # Preconfigured for clang # # Usage: make -f build/clang.mk .PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = clang CFLAGS = -O2 -Wall -Wextra CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s AR = ar ARFLAGS = cru RANLIB = ranlib LIBS = RM_F = rm -f MINITIFF_LIB = libminitiff.a MINITIFF_OBJS = tiffread.o tiffutil.o #tiffwrite.o TIFF2PNM = test/tiff2pnm$(EXEEXT) TIFF2PNM_OBJS = test/tiff2pnm.o all: $(MINITIFF_LIB) $(TIFF2PNM) test: $(TIFF2PNM) # TODO: run $(TIFF2PNM) check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< $(MINITIFF_LIB): $(MINITIFF_OBJS) $(AR) $(ARFLAGS) $@ $(MINITIFF_OBJS) $(RANLIB) $@ $(TIFF2PNM): $(TIFF2PNM_OBJS) $(MINITIFF_LIB) $(LD) $(LDFLAGS) -o $@ $(TIFF2PNM_OBJS) $(MINITIFF_LIB) $(LIBS) tiffread.o: tiffread.c minitiff.h tiffutil.o: tiffutil.c minitiff.h #tiffwrite.o: tiffwrite.c test/tiff2pnm.o: test/tiff2pnm.c minitiff.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o $@ $*.c clean: -$(RM_F) $(MINITIFF_LIB) $(MINITIFF_OBJS) -$(RM_F) $(TIFF2PNM) $(TIFF2PNM_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/minitiff/build/gcc.mk000066400000000000000000000021351343170417500177730ustar00rootroot00000000000000# gcc.mk # Generated from Makefile.in # Preconfigured for gcc # # Usage: make -f build/gcc.mk .PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = gcc CFLAGS = -O2 -Wall -Wextra CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s AR = ar ARFLAGS = cru RANLIB = ranlib LIBS = RM_F = rm -f MINITIFF_LIB = libminitiff.a MINITIFF_OBJS = tiffread.o tiffutil.o #tiffwrite.o TIFF2PNM = test/tiff2pnm$(EXEEXT) TIFF2PNM_OBJS = test/tiff2pnm.o all: $(MINITIFF_LIB) $(TIFF2PNM) test: $(TIFF2PNM) # TODO: run $(TIFF2PNM) check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< $(MINITIFF_LIB): $(MINITIFF_OBJS) $(AR) $(ARFLAGS) $@ $(MINITIFF_OBJS) $(RANLIB) $@ $(TIFF2PNM): $(TIFF2PNM_OBJS) $(MINITIFF_LIB) $(LD) $(LDFLAGS) -o $@ $(TIFF2PNM_OBJS) $(MINITIFF_LIB) $(LIBS) tiffread.o: tiffread.c minitiff.h tiffutil.o: tiffutil.c minitiff.h #tiffwrite.o: tiffwrite.c test/tiff2pnm.o: test/tiff2pnm.c minitiff.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o $@ $*.c clean: -$(RM_F) $(MINITIFF_LIB) $(MINITIFF_OBJS) -$(RM_F) $(TIFF2PNM) $(TIFF2PNM_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/minitiff/build/unix.mk000066400000000000000000000021321343170417500202170ustar00rootroot00000000000000# unix.mk # Generated from Makefile.in # Preconfigured for Unix (generic) # # Usage: make -f build/unix.mk .PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = cc CFLAGS = -O CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s AR = ar ARFLAGS = cru RANLIB = ranlib LIBS = RM_F = rm -f MINITIFF_LIB = libminitiff.a MINITIFF_OBJS = tiffread.o tiffutil.o #tiffwrite.o TIFF2PNM = test/tiff2pnm$(EXEEXT) TIFF2PNM_OBJS = test/tiff2pnm.o all: $(MINITIFF_LIB) $(TIFF2PNM) test: $(TIFF2PNM) # TODO: run $(TIFF2PNM) check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< $(MINITIFF_LIB): $(MINITIFF_OBJS) $(AR) $(ARFLAGS) $@ $(MINITIFF_OBJS) $(RANLIB) $@ $(TIFF2PNM): $(TIFF2PNM_OBJS) $(MINITIFF_LIB) $(LD) $(LDFLAGS) -o $@ $(TIFF2PNM_OBJS) $(MINITIFF_LIB) $(LIBS) tiffread.o: tiffread.c minitiff.h tiffutil.o: tiffutil.c minitiff.h #tiffwrite.o: tiffwrite.c test/tiff2pnm.o: test/tiff2pnm.c minitiff.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o $@ $*.c clean: -$(RM_F) $(MINITIFF_LIB) $(MINITIFF_OBJS) -$(RM_F) $(TIFF2PNM) $(TIFF2PNM_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/minitiff/build/visualc.mk000066400000000000000000000021431343170417500207040ustar00rootroot00000000000000# visualc.mk # Generated from Makefile.in # Preconfigured for Microsoft Visual C++ # # Usage: nmake -f build\visualc.mk CC = cl -nologo CFLAGS = -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -MD -O2 -W4 CPP = cl -nologo -E CPPFLAGS = LD = link -nologo LDFLAGS = AR = lib -nologo ARFLAGS = LIBS = RM_F = del /q MINITIFF_LIB = minitiff.lib MINITIFF_OBJS = tiffread.obj tiffutil.obj #tiffwrite.obj TIFF2PNM = test\tiff2pnm.exe TIFF2PNM_OBJS = test\tiff2pnm.obj all: $(MINITIFF_LIB) $(TIFF2PNM) test: $(TIFF2PNM) # TODO: run $(TIFF2PNM) check: test .c.obj: $(CC) -c $(CPPFLAGS) $(CFLAGS) -Fo$@ $< $(MINITIFF_LIB): $(MINITIFF_OBJS) $(AR) $(ARFLAGS) -out:$@ $(MINITIFF_OBJS) $(TIFF2PNM): $(TIFF2PNM_OBJS) $(MINITIFF_LIB) $(LD) $(LDFLAGS) -out:$@ $(TIFF2PNM_OBJS) $(MINITIFF_LIB) $(LIBS) tiffread.obj: tiffread.c minitiff.h tiffutil.obj: tiffutil.c minitiff.h #tiffwrite.obj: tiffwrite.c test\tiff2pnm.obj: test\tiff2pnm.c minitiff.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -Fo$@ $*.c clean: -$(RM_F) $(MINITIFF_LIB) $(MINITIFF_OBJS) -$(RM_F) $(TIFF2PNM) $(TIFF2PNM_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/minitiff/minitiff.h000066400000000000000000000240601343170417500175660ustar00rootroot00000000000000/* * minitiff.h * Minimal I/O interface to the Tagged Image File Format (TIFF). * Version 0.2 (draft). * * Copyright (C) 2006-2017 Cosmin Truta. * * minitiff is open-source software, distributed under the zlib license. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, 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 notice may not be removed or altered from any source distribution. */ #ifndef MINITIFF_H_ #define MINITIFF_H_ #include #ifdef __cplusplus extern "C" { #endif /* * The minitiff data structure. */ struct minitiff_info { void (*error_handler)(const char *msg); void (*warning_handler)(const char *msg); int byte_order; size_t width; size_t height; unsigned int bits_per_sample; unsigned int compression; unsigned int photometric; size_t strip_offsets_count; unsigned long *strip_offsets; unsigned int orientation; unsigned int samples_per_pixel; size_t rows_per_strip; }; /* * Constructor, validator and destructor. */ void minitiff_init_info(struct minitiff_info *info_ptr); void minitiff_validate_info(const struct minitiff_info *info_ptr); void minitiff_destroy_info(struct minitiff_info *info_ptr); /* * Input functions. */ void minitiff_read_info(struct minitiff_info *info_ptr, FILE *stream); void minitiff_read_row(struct minitiff_info *info_ptr, unsigned char *row_ptr, size_t row_index, FILE *stream); /* * Output functions. */ void minitiff_write_info(const struct minitiff_info *info_ptr, FILE *stream); void minitiff_write_row(const struct minitiff_info *info_ptr, const unsigned char *row_ptr, size_t row_index, FILE *stream); /* * Error-reporting functions. */ void minitiff_error(const struct minitiff_info *info_ptr, const char *msg); void minitiff_warning(const struct minitiff_info *info_ptr, const char *msg); /* * TIFF data type constants. */ enum { MINITIFF_TYPE_NONE = 0x0000, MINITIFF_TYPE_BYTE = 0x0001, /* 8-bit unsigned integer */ MINITIFF_TYPE_ASCII = 0x0002, /* null-terminated string of bytes */ MINITIFF_TYPE_SHORT = 0x0003, /* 16-bit unsigned integer */ MINITIFF_TYPE_LONG = 0x0004, /* 32-bit unsigned integer */ MINITIFF_TYPE_RATIONAL = 0x0005, /* 64-bit unsigned rational */ MINITIFF_TYPE_SBYTE = 0x0006, /* 8-bit signed integer */ MINITIFF_TYPE_UNDEFINED = 0x0007, /* blob of bytes */ MINITIFF_TYPE_SSHORT = 0x0008, /* 16-bit signed integer */ MINITIFF_TYPE_SLONG = 0x0009, /* 32-bit signed integer */ MINITIFF_TYPE_SRATIONAL = 0x000a, /* 64-bit signed rational */ MINITIFF_TYPE_FLOAT = 0x000b, /* 32-bit IEEE floating-point */ MINITIFF_TYPE_DOUBLE = 0x000c, /* 64-bit IEEE floating-point */ MINITIFF_TYPE_IFD = 0x000d, /* 32-bit file offset */ MINITIFF_TYPE_LONG64 = 0x0010, /* BigTIFF 64-bit unsigned integer */ MINITIFF_TYPE_SLONG64 = 0x0011, /* BigTIFF 64-bit signed integer */ MINITIFF_TYPE_IFD64 = 0x0012 /* BigTIFF 64-bit file offset */ }; /* * TIFF tag constants. */ enum { MINITIFF_TAG_SUBFILE_TYPE = 0x00fe, MINITIFF_TAG_OLD_SUBFILE_TYPE = 0x00ff, MINITIFF_TAG_WIDTH = 0x0100, MINITIFF_TAG_HEIGHT = 0x0101, MINITIFF_TAG_BITS_PER_SAMPLE = 0x0102, MINITIFF_TAG_COMPRESSION = 0x0103, MINITIFF_TAG_PHOTOMETRIC = 0x0106, MINITIFF_TAG_THRESHOLDING = 0x0107, MINITIFF_TAG_CELL_WIDTH = 0x0108, MINITIFF_TAG_CELL_LENGTH = 0x0109, MINITIFF_TAG_FILL_ORDER = 0x010a, MINITIFF_TAG_DOCUMENT_NAME = 0x010d, MINITIFF_TAG_IMAGE_DESCRIPTION = 0x010e, MINITIFF_TAG_MAKE = 0x010f, MINITIFF_TAG_MODEL = 0x0110, MINITIFF_TAG_STRIP_OFFSETS = 0x0111, MINITIFF_TAG_ORIENTATION = 0x0112, MINITIFF_TAG_SAMPLES_PER_PIXEL = 0x0115, MINITIFF_TAG_ROWS_PER_STRIP = 0x0116, MINITIFF_TAG_STRIP_BYTE_COUNTS = 0x0117, MINITIFF_TAG_MIN_SAMPLE_VALUE = 0x0118, MINITIFF_TAG_MAX_SAMPLE_VALUE = 0x0119, MINITIFF_TAG_X_RESOLUTION = 0x011a, MINITIFF_TAG_Y_RESOLUTION = 0x011b, MINITIFF_TAG_PLANAR_CONFIGURATION = 0x011c, MINITIFF_TAG_PAGE_NAME = 0x011d, MINITIFF_TAG_X_POSITION = 0x011e, MINITIFF_TAG_Y_POSITION = 0x011f, MINITIFF_TAG_RESOLUTION_UNIT = 0x0128, MINITIFF_TAG_PAGE_NUMBER = 0x0129, MINITIFF_TAG_TRANSFER_FUNCTION = 0x012d, MINITIFF_TAG_SOFTWARE = 0x0131, MINITIFF_TAG_DATE_TIME = 0x0132, MINITIFF_TAG_ARTIST = 0x013b, MINITIFF_TAG_HOST_COMPUTER = 0x013c, MINITIFF_TAG_PREDICTOR = 0x013d, MINITIFF_TAG_WHITE_POINT = 0x013e, MINITIFF_TAG_PRIMARY_CHROMATICITIES = 0x013f, MINITIFF_TAG_COLOR_MAP = 0x0140, MINITIFF_TAG_HALFTONE_HINTS = 0x0141, MINITIFF_TAG_TILE_WIDTH = 0x0142, MINITIFF_TAG_TILE_LENGTH = 0x0143, MINITIFF_TAG_TILE_OFFSETS = 0x0144, MINITIFF_TAG_BYTE_COUNTS = 0x0145, MINITIFF_TAG_XMP = 0x02bc, MINITIFF_TAG_COPYRIGHT = 0x8298, MINITIFF_TAG_IPTC = 0x83bb, MINITIFF_TAG_EXIF_IFD = 0x8769, MINITIFF_TAG_ICC_PROFILE = 0x8773, MINITIFF_TAG_GPS_IFD = 0x8825, MINITIFF_TAG_INTEROPERABILITY_IFD = 0xa005, MINITIFF_TAG_PRINT_IM = 0xc4a5 }; /* * TIFF compression constants. */ enum { MINITIFF_COMPRESSION_NONE = 0x0001, /* No compression */ MINITIFF_COMPRESSION_CCITT_RLE = 0x0002, /* CCITT Huffman RLE */ MINITIFF_COMPRESSION_CCITT_T4 = 0x0003, /* CCITT T.4 (Group 3 fax) */ MINITIFF_COMPRESSION_CCITT_FAX3 = 0x0003, /* CCITT T.4 (Group 3 fax) */ MINITIFF_COMPRESSION_CCITT_T6 = 0x0004, /* CCITT T.6 (Group 4 fax) */ MINITIFF_COMPRESSION_CCITT_FAX4 = 0x0004, /* CCITT T.6 (Group 4 fax) */ MINITIFF_COMPRESSION_LZW = 0x0005, /* Lempel, Zip & Welch */ MINITIFF_COMPRESSION_OLD_JPEG = 0x0006, /* Old JPEG DCT */ MINITIFF_COMPRESSION_JPEG = 0x0007, /* JPEG DCT */ MINITIFF_COMPRESSION_ADOBE_DEFLATE = 0x0008, /* Adobe Deflate */ MINITIFF_COMPRESSION_ITU_T85 = 0x0009, /* ITU-T T.85 (JBIG B/W) */ MINITIFF_COMPRESSION_ITU_T43 = 0x000a, /* ITU-T T.43 (JBIG color) */ MINITIFF_COMPRESSION_NEXT_RLE = 0x7ffe, /* NeXT 2-bit RLE */ MINITIFF_COMPRESSION_CCITT_RLEW = 0x8003, /* CCITT RLE, word align */ MINITIFF_COMPRESSION_PACKBITS = 0x8005, /* Apple PackBits RLE */ MINITIFF_COMPRESSION_THUNDERSCAN = 0x8029, /* ThunderScan 4-bit RLE */ MINITIFF_COMPRESSION_IT8_CT_MP = 0x807f, /* IT8-CT and -MP, padding */ MINITIFF_COMPRESSION_IT8_LW = 0x8080, /* IT8-LW, RLE */ MINITIFF_COMPRESSION_IT8_HC = 0x8081, /* IT8-HC (not -MP), RLE */ MINITIFF_COMPRESSION_IT8_BL = 0x8082, /* IT8-BL, RLE */ MINITIFF_COMPRESSION_PIXARFILM = 0x808c, /* PixarFilm 10-bit LZW */ MINITIFF_COMPRESSION_PIXARLOG = 0x808d, /* PixarLog 11-bit Deflate */ MINITIFF_COMPRESSION_DEFLATE = 0x80b2, /* Deflate */ MINITIFF_COMPRESSION_KODAK_DCS = 0x80b3, /* Kodak DCS */ MINITIFF_COMPRESSION_JBIG = 0x8765, /* JBIG */ MINITIFF_COMPRESSION_SGI_LOGLUV = 0x8774, /* SGI LogLuv 32-bit RLE */ MINITIFF_COMPRESSION_SGI_LOGLUV24 = 0x8775, /* SGI LogLuv 24-bit */ MINITIFF_COMPRESSION_JPEG2000 = 0x8798, /* JPEG-2000 */ MINITIFF_COMPRESSION_LZMA2 = 0x886d /* LZMA2 */ }; /* * TIFF photometric constants. */ enum { MINITIFF_PHOTOMETRIC_MINWHITE = 0x0000, /* Min. value is white */ MINITIFF_PHOTOMETRIC_MINBLACK = 0x0001, /* Max. value is black */ MINITIFF_PHOTOMETRIC_RGB = 0x0002, /* RGB colors */ MINITIFF_PHOTOMETRIC_PALETTE = 0x0003, /* Indexed color map */ MINITIFF_PHOTOMETRIC_MASK = 0x0004, /* Mask */ MINITIFF_PHOTOMETRIC_SEPARATED = 0x0005, /* Separated color planes */ MINITIFF_PHOTOMETRIC_YCBCR = 0x0006, /* ITU-R BT.601 YCbCr */ MINITIFF_PHOTOMETRIC_CIELAB = 0x0008, /* CIE L*a*b* */ MINITIFF_PHOTOMETRIC_ICCLAB = 0x0009, /* ICC L*a*b* (Technote 4) */ MINITIFF_PHOTOMETRIC_ITULAB = 0x000a, /* ITU L*a*b* */ MINITIFF_PHOTOMETRIC_CFA = 0x8023, /* Color Filter Array */ MINITIFF_PHOTOMETRIC_LOGL = 0x804c, /* CIE Log2(L) */ MINITIFF_PHOTOMETRIC_LOGLUV = 0x804d /* CIE Log2(L)u'v' */ }; /* * TIFF image orientation constants. */ enum { MINITIFF_ORIENTATION_TOP_LEFT = 0x0001, MINITIFF_ORIENTATION_TOP_RIGHT = 0x0002, MINITIFF_ORIENTATION_BOTTOM_RIGHT = 0x0003, MINITIFF_ORIENTATION_BOTTOM_LEFT = 0x0004, MINITIFF_ORIENTATION_LEFT_TOP = 0x0005, MINITIFF_ORIENTATION_RIGHT_TOP = 0x0006, MINITIFF_ORIENTATION_RIGHT_BOTTOM = 0x0007, MINITIFF_ORIENTATION_LEFT_BOTTOM = 0x0008 }; /* * TIFF file signature constants. */ extern const char minitiff_sig_m[4]; extern const char minitiff_sig_i[4]; extern const char minitiff_sig_bigm[4]; extern const char minitiff_sig_bigi[4]; #ifdef __cplusplus } /* extern "C" */ #endif #endif /* MINITIFF_H_ */ optipng-0.7.7/src/minitiff/test/000077500000000000000000000000001343170417500165655ustar00rootroot00000000000000optipng-0.7.7/src/minitiff/test/tiff2pnm.c000066400000000000000000000052101343170417500204540ustar00rootroot00000000000000/* * tiff2pnm.c * A test program for minitiff. * * Copyright (C) 2006-2017 Cosmin Truta. * * minitiff is open-source software, distributed under the zlib license. * For conditions of distribution and use, see copyright notice in minitiff.h. */ #include "minitiff.h" #include #include static int tiff2pnm(const char *in_path, const char *out_path) { FILE *in_stream; FILE *out_stream; struct minitiff_info info; size_t width, height, depth, y; unsigned char *row; int ioerr; in_stream = fopen(in_path, "rb"); if (in_stream == NULL) { fprintf(stderr, "error: Can't open input TIFF file: %s\n", in_path); return -1; } minitiff_init_info(&info); minitiff_read_info(&info, in_stream); minitiff_validate_info(&info); width = info.width; height = info.height; depth = info.samples_per_pixel; if (depth != 1 && depth != 3) { fprintf(stderr, "error: Invalid number of color planes in TIFF files: %lu\n", (unsigned long)depth); minitiff_destroy_info(&info); fclose(in_stream); return -1; } row = (unsigned char *)malloc(depth * width); if (row == NULL) { fprintf(stderr, "critical error: Out of memory\n"); minitiff_destroy_info(&info); fclose(in_stream); exit(EXIT_FAILURE); } out_stream = fopen(out_path, "wb"); if (out_stream != NULL) { ioerr = 0; fprintf(out_stream, "P%c\n%lu %lu\n255\n", (depth == 1) ? '5' : '6', (unsigned long)width, (unsigned long)height); for (y = 0; y < height; ++y) { minitiff_read_row(&info, row, y, in_stream); fwrite(row, depth, width, out_stream); } if (ferror(in_stream)) { ioerr = 1; fprintf(stderr, "error: Can't read input TIFF file: %s\n", in_path); } if (ferror(out_stream)) { ioerr = 1; fprintf(stderr, "error: Can't write output PNM file: %s\n", out_path); } fclose(out_stream); } else { ioerr = 1; fprintf(stderr, "error: Can't open output PNM file: %s\n", out_path); } minitiff_destroy_info(&info); fclose(in_stream); fclose(out_stream); return ioerr ? -1 : 1; } int main(int argc, char *argv[]) { if (argc <= 2) { fprintf(stderr, "usage: tiff2pnm input.tif output.pnm\n"); return EXIT_FAILURE; } return (tiff2pnm(argv[1], argv[2]) >= 0) ? EXIT_SUCCESS : EXIT_FAILURE; } optipng-0.7.7/src/minitiff/tiffread.c000066400000000000000000000343671343170417500175530ustar00rootroot00000000000000/* * tiffread.c * File input routines for minitiff. * * Copyright (C) 2006-2017 Cosmin Truta. * * minitiff is open-source software, distributed under the zlib license. * For conditions of distribution and use, see copyright notice in minitiff.h. */ #include "minitiff.h" #include #include #include /* * Error messages. */ static const char *msg_err_alloc = "Error allocating memory for TIFF file"; static const char *msg_err_read = "Error reading TIFF file"; static const char *msg_err_seek = "Error repositioning TIFF file"; static const char *msg_err_notiff = "Not a TIFF file"; static const char *msg_err_bigtiff = "Unsupported BigTIFF file"; static const char *msg_err_invalid = "Invalid TIFF file"; static const char *msg_err_range = "Value out of the supported range in TIFF file"; static const char *msg_err_unsupported = "Unsupported data in TIFF file"; static const char *msg_warn_metadata = "Unrecognized metadata in TIFF file"; static const char *msg_warn_multiple = "Selected first image from multi-image TIFF file"; /* * Memory reader structure. */ struct minitiff_getter { unsigned int (*get_ushort)(const unsigned char *buf_ptr); unsigned long (*get_ulong)(const unsigned char *buf_ptr); }; /* * Memory reader. */ static unsigned int get_ushort_m(const unsigned char *buf_ptr) { return ((unsigned int)buf_ptr[0] << 8) + ((unsigned int)buf_ptr[1]); } /* * Memory reader. */ static unsigned int get_ushort_i(const unsigned char *buf_ptr) { return ((unsigned int)buf_ptr[0]) + ((unsigned int)buf_ptr[1] << 8); } /* * Memory reader. */ static unsigned long get_ulong_m(const unsigned char *buf_ptr) { return ((unsigned long)buf_ptr[0] << 24) + ((unsigned long)buf_ptr[1] << 16) + ((unsigned long)buf_ptr[2] << 8) + ((unsigned long)buf_ptr[3]); } /* * Memory reader. */ static unsigned long get_ulong_i(const unsigned char *buf_ptr) { return ((unsigned long)buf_ptr[0]) + ((unsigned long)buf_ptr[1] << 8) + ((unsigned long)buf_ptr[2] << 16) + ((unsigned long)buf_ptr[3] << 24); } /* * Memory reader. */ static unsigned long get_ulong_value(const struct minitiff_getter *getter_ptr, int tag_type, const unsigned char *buf_ptr) { switch (tag_type) { case MINITIFF_TYPE_BYTE: return (unsigned long)buf_ptr[0]; case MINITIFF_TYPE_SHORT: return (unsigned long)getter_ptr->get_ushort(buf_ptr); case MINITIFF_TYPE_LONG: return getter_ptr->get_ulong(buf_ptr); default: return (unsigned long)-1L; /* error */ } } /* * Memory allocator. */ static unsigned long *alloc_ulong_array(struct minitiff_info *info_ptr, size_t count) { unsigned long *result; if (count > (size_t)(-1) / sizeof(unsigned long)) minitiff_error(info_ptr, msg_err_range); result = (unsigned long *)malloc(count * sizeof(unsigned long)); if (result == NULL) minitiff_error(info_ptr, msg_err_alloc); return result; } /* * Type-casting utilities. */ #if UINT_MAX >= 0xffffffffUL #define cast_ulong_to_uint(info_ptr, value) ((unsigned int)(value)) #define cast_ulong_to_size(info_ptr, value) ((size_t)(value)) #else static unsigned int cast_ulong_to_uint(struct minitiff_info *info_ptr, unsigned long value) { unsigned int result = (unsigned int)value; if (result != value) minitiff_error(info_ptr, msg_err_range); return result; } #define cast_ulong_to_size(info_ptr, value) \ ((size_t)cast_ulong_to_uint(info_ptr, value)) #endif /* * File reader. */ static size_t read_ulong_values(const struct minitiff_getter *getter_ptr, int tag_type, unsigned long values[], size_t count, FILE *stream) { unsigned char buf[4]; size_t value_size; size_t i; switch (tag_type) { case MINITIFF_TYPE_BYTE: value_size = 1; break; case MINITIFF_TYPE_SHORT: value_size = 2; break; case MINITIFF_TYPE_LONG: value_size = 4; break; default: return 0; /* read nothing */ } for (i = 0; i < count; ++i) { if (fread(buf, value_size, 1, stream) != 1) break; values[i] = get_ulong_value(getter_ptr, tag_type, buf); } return i; } /* * File seeker. */ static void seek_to_offset(struct minitiff_info *info_ptr, long offset, FILE *stream) { if (offset < 0) minitiff_error(info_ptr, msg_err_range); if (ftell(stream) == offset) return; if (fseek(stream, offset, SEEK_SET) != 0) minitiff_error(info_ptr, msg_err_seek); } /* * TIFF structure reader. */ void minitiff_read_info(struct minitiff_info *info_ptr, FILE *stream) { struct minitiff_getter getter; unsigned char buf[12]; unsigned char *vbuf = buf + 8; unsigned long ulvals[4], ulval; long dir_offset; unsigned int dir_size, i; unsigned int tag_id, tag_type; size_t count; size_t bits_per_sample_count; unsigned int bits_per_sample_tag_type, strip_offsets_tag_type; long bits_per_sample_offset, strip_offsets_offset; int unknown_metadata_found; /* Read the TIFF header. */ if (fread(buf, 8, 1, stream) != 1) goto err_read; if (memcmp(buf, minitiff_sig_m, 4) == 0) { info_ptr->byte_order = 'M'; getter.get_ushort = get_ushort_m; getter.get_ulong = get_ulong_m; } else if (memcmp(buf, minitiff_sig_i, 4) == 0) { info_ptr->byte_order = 'I'; getter.get_ushort = get_ushort_i; getter.get_ulong = get_ulong_i; } else if (memcmp(buf, minitiff_sig_bigm, 4) == 0 || memcmp(buf, minitiff_sig_bigi, 4) == 0) { minitiff_error(info_ptr, msg_err_bigtiff); return; } else { minitiff_error(info_ptr, msg_err_notiff); return; } bits_per_sample_count = 0; bits_per_sample_tag_type = strip_offsets_tag_type = 0; bits_per_sample_offset = strip_offsets_offset = 0; dir_offset = (long)getter.get_ulong(buf + 4); if (dir_offset >= 0 && dir_offset < 8) goto err_invalid; seek_to_offset(info_ptr, dir_offset, stream); /* Read the TIFF directory. */ if (fread(buf, 2, 1, stream) != 1) goto err_read; dir_size = getter.get_ushort(buf); unknown_metadata_found = 0; for (i = 0; i < dir_size; ++i) { if (fread(buf, 12, 1, stream) != 1) goto err_read; tag_id = getter.get_ushort(buf); tag_type = getter.get_ushort(buf + 2); count = cast_ulong_to_size(info_ptr, getter.get_ulong(buf + 4)); if (count == 0) goto err_unsupported; switch (tag_id) { case MINITIFF_TAG_SUBFILE_TYPE: if (count != 1) goto err_unsupported; ulval = get_ulong_value(&getter, tag_type, vbuf); if (ulval != 0 && ulval != 1) goto err_unsupported; break; case MINITIFF_TAG_WIDTH: if (count != 1) goto err_unsupported; ulval = get_ulong_value(&getter, tag_type, vbuf); info_ptr->width = cast_ulong_to_size(info_ptr, ulval); break; case MINITIFF_TAG_HEIGHT: if (count != 1) goto err_unsupported; ulval = get_ulong_value(&getter, tag_type, vbuf); info_ptr->height = cast_ulong_to_size(info_ptr, ulval); break; case MINITIFF_TAG_BITS_PER_SAMPLE: if (count == 1) { ulval = get_ulong_value(&getter, tag_type, vbuf); info_ptr->bits_per_sample = cast_ulong_to_uint(info_ptr, ulval); } else { bits_per_sample_count = count; bits_per_sample_tag_type = tag_type; bits_per_sample_offset = (long)getter.get_ulong(vbuf); } break; case MINITIFF_TAG_COMPRESSION: if (count != 1) goto err_unsupported; ulval = get_ulong_value(&getter, tag_type, vbuf); info_ptr->compression = cast_ulong_to_uint(info_ptr, ulval); break; case MINITIFF_TAG_PHOTOMETRIC: if (count != 1) goto err_unsupported; ulval = get_ulong_value(&getter, tag_type, vbuf); info_ptr->photometric = cast_ulong_to_uint(info_ptr, ulval); break; case MINITIFF_TAG_STRIP_OFFSETS: info_ptr->strip_offsets_count = count; if (count == 1) { if (info_ptr->strip_offsets != NULL) goto err_invalid; info_ptr->strip_offsets = alloc_ulong_array(info_ptr, 1); info_ptr->strip_offsets[0] = get_ulong_value(&getter, tag_type, vbuf); } else { strip_offsets_tag_type = tag_type; strip_offsets_offset = (long)getter.get_ulong(vbuf); } break; case MINITIFF_TAG_ORIENTATION: if (count != 1) goto err_unsupported; ulval = get_ulong_value(&getter, tag_type, vbuf); info_ptr->orientation = cast_ulong_to_uint(info_ptr, ulval); break; case MINITIFF_TAG_SAMPLES_PER_PIXEL: if (count != 1) goto err_unsupported; ulval = get_ulong_value(&getter, tag_type, vbuf); info_ptr->samples_per_pixel = cast_ulong_to_uint(info_ptr, ulval); break; case MINITIFF_TAG_ROWS_PER_STRIP: if (count != 1) goto err_unsupported; ulval = get_ulong_value(&getter, tag_type, vbuf); info_ptr->rows_per_strip = cast_ulong_to_size(info_ptr, ulval); break; case MINITIFF_TAG_STRIP_BYTE_COUNTS: /* ignored for uncompressed images */ break; case MINITIFF_TAG_PLANAR_CONFIGURATION: case MINITIFF_TAG_PREDICTOR: if (count != 1 || get_ulong_value(&getter, tag_type, vbuf) != 1) goto err_unsupported; break; case MINITIFF_TAG_XMP: case MINITIFF_TAG_IPTC: case MINITIFF_TAG_EXIF_IFD: case MINITIFF_TAG_ICC_PROFILE: case MINITIFF_TAG_GPS_IFD: case MINITIFF_TAG_INTEROPERABILITY_IFD: case MINITIFF_TAG_PRINT_IM: if (!unknown_metadata_found) { unknown_metadata_found = 1; minitiff_warning(info_ptr, msg_warn_metadata); } break; } } /* Is this the last TIFF directory? */ if (fread(buf, 4, 1, stream) != 1) goto err_read; if (getter.get_ulong(buf) != 0) minitiff_warning(info_ptr, msg_warn_multiple); /* Finish up the incomplete readings. */ if (bits_per_sample_offset != 0) { count = bits_per_sample_count; if (count != info_ptr->samples_per_pixel) goto err_invalid; if (count > 4) goto err_unsupported; seek_to_offset(info_ptr, bits_per_sample_offset, stream); if (read_ulong_values(&getter, bits_per_sample_tag_type, ulvals, count, stream) != count) goto err_read; while (--count > 0) if (ulvals[0] != ulvals[count]) goto err_unsupported; info_ptr->bits_per_sample = cast_ulong_to_uint(info_ptr, ulvals[0]); } if (strip_offsets_offset != 0) { count = info_ptr->strip_offsets_count; if (count == 0 || count > info_ptr->height) goto err_invalid; if (info_ptr->strip_offsets != NULL) goto err_invalid; info_ptr->strip_offsets = alloc_ulong_array(info_ptr, count); seek_to_offset(info_ptr, strip_offsets_offset, stream); if (read_ulong_values(&getter, strip_offsets_tag_type, info_ptr->strip_offsets, count, stream) != count) goto err_read; } /* Return successfully. */ return; /* Quick and dirty goto labels. */ err_read: minitiff_error(info_ptr, msg_err_read); err_invalid: minitiff_error(info_ptr, msg_err_invalid); err_unsupported: minitiff_error(info_ptr, msg_err_unsupported); } /* * TIFF row reader. */ void minitiff_read_row(struct minitiff_info *info_ptr, unsigned char *row_ptr, size_t row_index, FILE *stream) { size_t row_size, strip_index; unsigned int bytes_per_sample, sample_max; long offset; size_t i; /* Do not do validation here. */ /* Call minitiff_validate_info() before calling this function. */ bytes_per_sample = (info_ptr->bits_per_sample + 7) / 8; row_size = info_ptr->width * info_ptr->samples_per_pixel * bytes_per_sample; /* Position the file pointer to the beginning of the row, * if that has not been done already. */ strip_index = row_index / info_ptr->rows_per_strip; if (strip_index >= info_ptr->strip_offsets_count) goto err_invalid; if ((long)info_ptr->strip_offsets[strip_index] < 0) goto err_range; offset = (long)(info_ptr->strip_offsets[strip_index] + row_size * (row_index % info_ptr->rows_per_strip)); seek_to_offset(info_ptr, offset, stream); /* Read the row, and do all the necessary adjustments. */ if (fread(row_ptr, row_size, 1, stream) != 1) goto err_read; if (info_ptr->photometric == 0) { /* White is zero. */ if (bytes_per_sample > 1) goto err_unsupported; sample_max = (1 << info_ptr->bits_per_sample) - 1; for (i = 0; i < row_size; ++i) row_ptr[i] = (unsigned char)(sample_max - row_ptr[i]); } /* Return successfully. */ return; /* Quick and dirty goto labels. */ err_read: minitiff_error(info_ptr, msg_err_read); err_invalid: minitiff_error(info_ptr, msg_err_invalid); err_range: minitiff_error(info_ptr, msg_err_range); err_unsupported: minitiff_error(info_ptr, msg_err_unsupported); } optipng-0.7.7/src/minitiff/tiffutil.c000066400000000000000000000052571343170417500176110ustar00rootroot00000000000000/* * tiffutil.c * General-purpose routines for minitiff. * * Copyright (C) 2006-2017 Cosmin Truta. * * minitiff is open-source software, distributed under the zlib license. * For conditions of distribution and use, see copyright notice in minitiff.h. */ #include "minitiff.h" #include #include #include /* * Constructor. */ void minitiff_init_info(struct minitiff_info *info_ptr) { memset(info_ptr, 0, sizeof(*info_ptr)); info_ptr->photometric = (unsigned int)(-1); } /* * Validator. */ void minitiff_validate_info(const struct minitiff_info *info_ptr) { if (info_ptr->width == 0 || info_ptr->height == 0) minitiff_error(info_ptr, "Invalid image dimensions in TIFF file"); if (info_ptr->bits_per_sample == 0 || info_ptr->samples_per_pixel == 0) minitiff_error(info_ptr, "Invalid pixel info in TIFF file"); if (info_ptr->strip_offsets == NULL || info_ptr->rows_per_strip == 0) minitiff_error(info_ptr, "Invalid strip info in TIFF file"); if (info_ptr->compression != MINITIFF_COMPRESSION_NONE) minitiff_error(info_ptr, "Unsupported compression method in TIFF file"); if (info_ptr->photometric >= MINITIFF_PHOTOMETRIC_PALETTE) minitiff_error(info_ptr, "Unsupported photometric interpretation in TIFF file"); } /* * Destructor. */ void minitiff_destroy_info(struct minitiff_info *info_ptr) { if (info_ptr->strip_offsets != NULL) free(info_ptr->strip_offsets); } /* * Error handling utility. */ static void default_error_handler(const char *msg) { fprintf(stderr, "minitiff: error: %s\n", msg); exit(EXIT_FAILURE); } /* * Error handler. */ void minitiff_error(const struct minitiff_info *info_ptr, const char *msg) { if (info_ptr->error_handler != NULL) info_ptr->error_handler(msg); else default_error_handler(msg); abort(); } /* * Warning handling utility. */ static void default_warning_handler(const char *msg) { fprintf(stderr, "minitiff: warning: %s\n", msg); } /* * Warning handler. */ void minitiff_warning(const struct minitiff_info *info_ptr, const char *msg) { if (info_ptr->warning_handler != NULL) info_ptr->warning_handler(msg); else default_warning_handler(msg); } /* * Global constants: TIFF file signature. */ const char minitiff_sig_m[4] = { 0x4d, 0x4d, 0x00, 0x2a }; /* "MM\0*" */ const char minitiff_sig_i[4] = { 0x49, 0x49, 0x2a, 0x00 }; /* "II*\0" */ /* * Global constants: BigTIFF file signature. */ const char minitiff_sig_bigm[4] = { 0x4d, 0x4d, 0x00, 0x2b }; /* "MM\0*" */ const char minitiff_sig_bigi[4] = { 0x49, 0x49, 0x2b, 0x00 }; /* "II*\0" */ optipng-0.7.7/src/minitiff/tiffwrite.c000066400000000000000000000005311343170417500177540ustar00rootroot00000000000000/* * tiffwrite.c * File output routines for minitiff. * * Copyright (C) 2006-2017 Cosmin Truta. * * minitiff is open-source software, distributed under the zlib license. * For conditions of distribution and use, see copyright notice in minitiff.h. */ #include "minitiff.h" #if 0 #error No file writing has been implemented yet. #endif optipng-0.7.7/src/opngreduc/000077500000000000000000000000001343170417500157675ustar00rootroot00000000000000optipng-0.7.7/src/opngreduc/Makefile.in000066400000000000000000000020161343170417500200330ustar00rootroot00000000000000.PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = @CC@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ LD = @LD@ LDFLAGS = @LDFLAGS@ AR = @AR@ ARFLAGS = @ARFLAGS@ RANLIB = @RANLIB@ RM_F = @RM_F@ @USE_SYSTEM_ZLIB_FALSE@ZDIR = ../zlib @USE_SYSTEM_LIBPNG_FALSE@PNGDIR = ../libpng OPNGREDUC_LIB = libopngreduc.a OPNGREDUC_OBJS = opngreduc.o @USE_SYSTEM_ZLIB_FALSE@OPNGREDUC_DEPINCLUDE_ZLIB = -I$(ZDIR) @USE_SYSTEM_ZLIB_TRUE@OPNGREDUC_DEPINCLUDE_ZLIB = @USE_SYSTEM_LIBPNG_FALSE@OPNGREDUC_DEPINCLUDE_LIBPNG = -I$(PNGDIR) @USE_SYSTEM_LIBPNG_TRUE@OPNGREDUC_DEPINCLUDE_LIBPNG = OPNGREDUC_DEPINCLUDES = \ $(OPNGREDUC_DEPINCLUDE_ZLIB) \ $(OPNGREDUC_DEPINCLUDE_LIBPNG) all: $(OPNGREDUC_LIB) test: check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(OPNGREDUC_DEPINCLUDES) -o $@ $< $(OPNGREDUC_LIB): $(OPNGREDUC_OBJS) $(AR) $(ARFLAGS) $@ $(OPNGREDUC_OBJS) $(RANLIB) $@ opngreduc.o: opngreduc.c opngreduc.h clean: -$(RM_F) $(OPNGREDUC_LIB) $(OPNGREDUC_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/opngreduc/README.optipng.txt000066400000000000000000000004731343170417500211500ustar00rootroot00000000000000Name: opngreduc Summary: libpng extension: lossless image reductions Author: Cosmin Truta License: the libpng license (zlib-like); see ../libpng/LICENSE Limitations: - The color palette reductions are implemented only partially. - The bit depth reductions below 8, for grayscale images, are not implemented yet. optipng-0.7.7/src/opngreduc/build/000077500000000000000000000000001343170417500170665ustar00rootroot00000000000000optipng-0.7.7/src/opngreduc/build/bcc32.mk000066400000000000000000000015451343170417500203200ustar00rootroot00000000000000# bcc32.mk # Generated from Makefile.in # Preconfigured for Borland C++ # # Usage: make -f build\bcc32.mk CC = bcc32 CFLAGS = -O2 -d -k- -w CPP = #cpp32 -P- CPPFLAGS = LD = $(CC) LDFLAGS = $(CFLAGS) AR = tlib ARFLAGS = /C RM_F = del /q ZDIR = ..\zlib PNGDIR = ..\libpng OPNGREDUC_LIB = opngreduc.lib OPNGREDUC_OBJS = opngreduc.obj OPNGREDUC_LIBOBJS = +opngreduc.obj OPNGREDUC_DEPINCLUDE_ZLIB = -I$(ZDIR) OPNGREDUC_DEPINCLUDE_LIBPNG = -I$(PNGDIR) OPNGREDUC_DEPINCLUDES = \ $(OPNGREDUC_DEPINCLUDE_ZLIB) \ $(OPNGREDUC_DEPINCLUDE_LIBPNG) all: $(OPNGREDUC_LIB) test: check: test .c.obj: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(OPNGREDUC_DEPINCLUDES) -o$@ $< $(OPNGREDUC_LIB): $(OPNGREDUC_OBJS) $(AR) $(ARFLAGS) $@ $(OPNGREDUC_LIBOBJS) opngreduc.obj: opngreduc.c opngreduc.h clean: -$(RM_F) $(OPNGREDUC_LIB) $(OPNGREDUC_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/opngreduc/build/clang.mk000066400000000000000000000017301343170417500205040ustar00rootroot00000000000000# clang.mk # Generated from Makefile.in # Preconfigured for clang # # Usage: make -f build/clang.mk .PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = clang CFLAGS = -O2 -Wall -Wextra CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s AR = ar ARFLAGS = cru RANLIB = ranlib RM_F = rm -f ZDIR = ../zlib PNGDIR = ../libpng OPNGREDUC_LIB = libopngreduc.a OPNGREDUC_OBJS = opngreduc.o OPNGREDUC_DEPINCLUDE_ZLIB = -I$(ZDIR) #OPNGREDUC_DEPINCLUDE_ZLIB = OPNGREDUC_DEPINCLUDE_LIBPNG = -I$(PNGDIR) #OPNGREDUC_DEPINCLUDE_LIBPNG = OPNGREDUC_DEPINCLUDES = \ $(OPNGREDUC_DEPINCLUDE_ZLIB) \ $(OPNGREDUC_DEPINCLUDE_LIBPNG) all: $(OPNGREDUC_LIB) test: check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(OPNGREDUC_DEPINCLUDES) -o $@ $< $(OPNGREDUC_LIB): $(OPNGREDUC_OBJS) $(AR) $(ARFLAGS) $@ $(OPNGREDUC_OBJS) $(RANLIB) $@ opngreduc.o: opngreduc.c opngreduc.h clean: -$(RM_F) $(OPNGREDUC_LIB) $(OPNGREDUC_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/opngreduc/build/gcc.mk000066400000000000000000000017201343170417500201530ustar00rootroot00000000000000# gcc.mk # Generated from Makefile.in # Preconfigured for gcc # # Usage: make -f build/gcc.mk .PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = gcc CFLAGS = -O2 -Wall -Wextra CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s AR = ar ARFLAGS = cru RANLIB = ranlib RM_F = rm -f ZDIR = ../zlib PNGDIR = ../libpng OPNGREDUC_LIB = libopngreduc.a OPNGREDUC_OBJS = opngreduc.o OPNGREDUC_DEPINCLUDE_ZLIB = -I$(ZDIR) #OPNGREDUC_DEPINCLUDE_ZLIB = OPNGREDUC_DEPINCLUDE_LIBPNG = -I$(PNGDIR) #OPNGREDUC_DEPINCLUDE_LIBPNG = OPNGREDUC_DEPINCLUDES = \ $(OPNGREDUC_DEPINCLUDE_ZLIB) \ $(OPNGREDUC_DEPINCLUDE_LIBPNG) all: $(OPNGREDUC_LIB) test: check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(OPNGREDUC_DEPINCLUDES) -o $@ $< $(OPNGREDUC_LIB): $(OPNGREDUC_OBJS) $(AR) $(ARFLAGS) $@ $(OPNGREDUC_OBJS) $(RANLIB) $@ opngreduc.o: opngreduc.c opngreduc.h clean: -$(RM_F) $(OPNGREDUC_LIB) $(OPNGREDUC_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/opngreduc/build/unix.mk000066400000000000000000000017151343170417500204060ustar00rootroot00000000000000# unix.mk # Generated from Makefile.in # Preconfigured for Unix (generic) # # Usage: make -f build/unix.mk .PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = cc CFLAGS = -O CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s AR = ar ARFLAGS = cru RANLIB = ranlib RM_F = rm -f ZDIR = ../zlib PNGDIR = ../libpng OPNGREDUC_LIB = libopngreduc.a OPNGREDUC_OBJS = opngreduc.o OPNGREDUC_DEPINCLUDE_ZLIB = -I$(ZDIR) #OPNGREDUC_DEPINCLUDE_ZLIB = OPNGREDUC_DEPINCLUDE_LIBPNG = -I$(PNGDIR) #OPNGREDUC_DEPINCLUDE_LIBPNG = OPNGREDUC_DEPINCLUDES = \ $(OPNGREDUC_DEPINCLUDE_ZLIB) \ $(OPNGREDUC_DEPINCLUDE_LIBPNG) all: $(OPNGREDUC_LIB) test: check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(OPNGREDUC_DEPINCLUDES) -o $@ $< $(OPNGREDUC_LIB): $(OPNGREDUC_OBJS) $(AR) $(ARFLAGS) $@ $(OPNGREDUC_OBJS) $(RANLIB) $@ opngreduc.o: opngreduc.c opngreduc.h clean: -$(RM_F) $(OPNGREDUC_LIB) $(OPNGREDUC_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/opngreduc/build/visualc.mk000066400000000000000000000016211343170417500210650ustar00rootroot00000000000000# visualc.mk # Generated from Makefile.in # Preconfigured for Microsoft Visual C++ # # Usage: nmake -f build\visualc.mk CC = cl -nologo CFLAGS = -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -MD -O2 -W4 CPP = cl -nologo -E CPPFLAGS = LD = link -nologo LDFLAGS = AR = lib -nologo ARFLAGS = RM_F = del /q ZDIR = ..\zlib PNGDIR = ..\libpng OPNGREDUC_LIB = opngreduc.lib OPNGREDUC_OBJS = opngreduc.obj OPNGREDUC_DEPINCLUDE_ZLIB = -I$(ZDIR) OPNGREDUC_DEPINCLUDE_LIBPNG = -I$(PNGDIR) OPNGREDUC_DEPINCLUDES = \ $(OPNGREDUC_DEPINCLUDE_ZLIB) \ $(OPNGREDUC_DEPINCLUDE_LIBPNG) all: $(OPNGREDUC_LIB) test: check: test .c.obj: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(OPNGREDUC_DEPINCLUDES) -Fo$@ $< $(OPNGREDUC_LIB): $(OPNGREDUC_OBJS) $(AR) $(ARFLAGS) -out:$@ $(OPNGREDUC_OBJS) opngreduc.obj: opngreduc.c opngreduc.h clean: -$(RM_F) $(OPNGREDUC_LIB) $(OPNGREDUC_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/opngreduc/opngreduc.c000066400000000000000000001217541343170417500201330ustar00rootroot00000000000000/* * opngreduc.c - libpng extension: lossless image reductions. * * Copyright (C) 2003-2014 Cosmin Truta. * This software is distributed under the same licensing and warranty terms * as libpng. */ /* CAUTION: * Image reductions do not work well under certain transformations. * * Transformations like PNG_BGR, PNG_SWAP_BYTES, PNG_FILLER, PNG_INVERT_ALPHA, * and possibly others, require special treatment. However, the libpng API * does not currently convey the effect of transformations on its internal * state or on the layout of pixel data. * * Transformations which affect pixel depth (e.g. PNG_FILLER) are especially * dangerous when used in conjunction with this code, and should be avoided. */ #include "opngreduc.h" #include #ifndef OPNG_ASSERT #include #define OPNG_ASSERT(cond) assert(cond) #define OPNG_ASSERT_MSG(cond, msg) assert(cond) #endif #ifdef png_debug #define opng_debug(level, msg) png_debug(level, msg) #else #define opng_debug(level, msg) ((void)0) #endif #ifdef PNG_INFO_IMAGE_SUPPORTED /* * Check if the image information is valid. * The image information is said to be valid if all the required * critical chunk data is present in the png structures. * The function returns 1 if this information is valid, and 0 otherwise. */ int PNGAPI opng_validate_image(png_structp png_ptr, png_infop info_ptr) { opng_debug(1, "in opng_validate_image"); /* Validate IHDR. */ if (png_get_bit_depth(png_ptr, info_ptr) == 0) return 0; /* Validate PLTE. */ if (png_get_color_type(png_ptr, info_ptr) & PNG_COLOR_MASK_PALETTE) { if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_PLTE)) return 0; } /* Validate IDAT. */ if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_IDAT)) return 0; return 1; } #endif /* PNG_INFO_IMAGE_SUPPORTED */ #ifdef OPNG_IMAGE_REDUCTIONS_SUPPORTED #define OPNG_CMP_RGB(R1, G1, B1, R2, G2, B2) \ (((int)(R1) != (int)(R2)) ? \ ((int)(R1) - (int)(R2)) : \ (((int)(G1) != (int)(G2)) ? \ ((int)(G1) - (int)(G2)) : \ ((int)(B1) - (int)(B2)))) #define OPNG_CMP_ARGB(A1, R1, G1, B1, A2, R2, G2, B2) \ (((int)(A1) != (int)(A2)) ? \ ((int)(A1) - (int)(A2)) : \ (((int)(R1) != (R2)) ? \ ((int)(R1) - (int)(R2)) : \ (((int)(G1) != (int)(G2)) ? \ ((int)(G1) - (int)(G2)) : \ ((int)(B1) - (int)(B2))))) /* * Build a color+alpha palette in which the entries are sorted by * (alpha, red, green, blue), in this particular order. * Use the insertion sort algorithm. * The alpha value is ignored if it is not in the range [0 .. 255]. * The function returns: * 1 if the insertion is successful; *index = position of new entry. * 0 if the insertion is unnecessary; *index = position of crt entry. * -1 if overflow; *num_palette = *num_trans = *index = -1. */ static int /* PRIVATE */ opng_insert_palette_entry(png_colorp palette, int *num_palette, png_bytep trans_alpha, int *num_trans, int max_tuples, unsigned int red, unsigned int green, unsigned int blue, unsigned int alpha, int *index) { int low, high, mid, cmp; int i; OPNG_ASSERT(*num_palette >= 0 && *num_palette <= max_tuples); OPNG_ASSERT(*num_trans >= 0 && *num_trans <= *num_palette); if (alpha < 255) { /* Do a binary search among transparent tuples. */ low = 0; high = *num_trans - 1; while (low <= high) { mid = (low + high) / 2; cmp = OPNG_CMP_ARGB(alpha, red, green, blue, trans_alpha[mid], palette[mid].red, palette[mid].green, palette[mid].blue); if (cmp < 0) high = mid - 1; else if (cmp > 0) low = mid + 1; else { *index = mid; return 0; } } } else /* alpha == 255 || alpha not in [0 .. 255] */ { /* Do a (faster) binary search among opaque tuples. */ low = *num_trans; high = *num_palette - 1; while (low <= high) { mid = (low + high) / 2; cmp = OPNG_CMP_RGB(red, green, blue, palette[mid].red, palette[mid].green, palette[mid].blue); if (cmp < 0) high = mid - 1; else if (cmp > 0) low = mid + 1; else { *index = mid; return 0; } } } if (alpha > 255) { /* The binary search among opaque tuples has failed. */ /* Do a linear search among transparent tuples, ignoring alpha. */ for (i = 0; i < *num_trans; ++i) { cmp = OPNG_CMP_RGB(red, green, blue, palette[i].red, palette[i].green, palette[i].blue); if (cmp == 0) { *index = i; return 0; } } } /* Check for overflow. */ if (*num_palette >= max_tuples) { *num_palette = *num_trans = *index = -1; return -1; } /* Insert new tuple at [low]. */ OPNG_ASSERT(low >= 0 && low <= *num_palette); for (i = *num_palette; i > low; --i) palette[i] = palette[i - 1]; palette[low].red = (png_byte)red; palette[low].green = (png_byte)green; palette[low].blue = (png_byte)blue; ++(*num_palette); if (alpha < 255) { OPNG_ASSERT(low <= *num_trans); for (i = *num_trans; i > low; --i) trans_alpha[i] = trans_alpha[i - 1]; trans_alpha[low] = (png_byte)alpha; ++(*num_trans); } *index = low; return 1; } /* * Change the size of the palette buffer. * Changing info_ptr->num_palette directly, avoiding reallocation, should * have been sufficient, but can't be done using the current libpng API. */ static void /* PRIVATE */ opng_realloc_PLTE(png_structp png_ptr, png_infop info_ptr, int num_palette) { png_color buffer[PNG_MAX_PALETTE_LENGTH]; png_colorp palette; int src_num_palette; opng_debug(1, "in opng_realloc_PLTE"); OPNG_ASSERT(num_palette > 0); src_num_palette = 0; png_get_PLTE(png_ptr, info_ptr, &palette, &src_num_palette); if (num_palette == src_num_palette) return; memcpy(buffer, palette, num_palette * sizeof(png_color)); if (num_palette > src_num_palette) memset(buffer + src_num_palette, 0, (num_palette - src_num_palette) * sizeof(png_color)); png_set_PLTE(png_ptr, info_ptr, buffer, num_palette); } /* * Change the size of the transparency buffer. * Changing info_ptr->num_trans directly, avoiding reallocation, should * have been sufficient, but can't be done using the current libpng API. */ static void /* PRIVATE */ opng_realloc_tRNS(png_structp png_ptr, png_infop info_ptr, int num_trans) { png_byte buffer[PNG_MAX_PALETTE_LENGTH]; png_bytep trans_alpha; int src_num_trans; opng_debug(1, "in opng_realloc_tRNS"); OPNG_ASSERT(num_trans > 0); /* tRNS should be invalidated in this case */ src_num_trans = 0; png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &src_num_trans, NULL); if (num_trans == src_num_trans) return; memcpy(buffer, trans_alpha, (size_t)num_trans); if (num_trans > src_num_trans) memset(buffer + src_num_trans, 0, num_trans - src_num_trans); png_set_tRNS(png_ptr, info_ptr, buffer, num_trans, NULL); } /* * Retrieve the alpha samples from the given image row. */ static void /* PRIVATE */ opng_get_alpha_row(png_row_infop row_info_ptr, png_color_16p trans_color, png_bytep row, png_bytep alpha_row) { png_bytep sample_ptr; png_uint_32 width; int color_type, bit_depth, channels; png_byte trans_red, trans_green, trans_blue, trans_gray; png_uint_32 i; width = row_info_ptr->width; color_type = row_info_ptr->color_type; bit_depth = row_info_ptr->bit_depth; channels = row_info_ptr->channels; OPNG_ASSERT(!(color_type & PNG_COLOR_MASK_PALETTE)); OPNG_ASSERT(bit_depth == 8); if (!(color_type & PNG_COLOR_MASK_ALPHA)) { if (trans_color == NULL) { /* All pixels are fully opaque. */ memset(alpha_row, 255, (size_t)width); return; } if (color_type == PNG_COLOR_TYPE_RGB) { OPNG_ASSERT(channels == 3); trans_red = (png_byte)trans_color->red; trans_green = (png_byte)trans_color->green; trans_blue = (png_byte)trans_color->blue; sample_ptr = row; for (i = 0; i < width; ++i, sample_ptr += 3) alpha_row[i] = (png_byte) ((sample_ptr[0] == trans_red && sample_ptr[1] == trans_green && sample_ptr[2] == trans_blue) ? 0 : 255); } else { OPNG_ASSERT(color_type == PNG_COLOR_TYPE_GRAY); OPNG_ASSERT(channels == 1); trans_gray = (png_byte)trans_color->gray; for (i = 0; i < width; ++i) alpha_row[i] = (png_byte)((row[i] == trans_gray) ? 0 : 255); } return; } /* There is a real alpha channel. The alpha sample is last in RGBA tuple. */ OPNG_ASSERT(channels > 1); sample_ptr = row + (channels - 1); for (i = 0; i < width; ++i, sample_ptr += channels, ++alpha_row) *alpha_row = *sample_ptr; } /* * Analyze the redundancy of bits inside the image. * The parameter reductions indicates the intended reductions. * The function returns the possible reductions. */ static png_uint_32 /* PRIVATE */ opng_analyze_bits(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions) { png_bytepp row_ptr; png_bytep component_ptr; png_uint_32 height, width; int bit_depth, color_type, byte_depth, channels, sample_size, offset_alpha; #ifdef PNG_bKGD_SUPPORTED png_color_16p background; #endif png_uint_32 i, j; opng_debug(1, "in opng_analyze_bits"); png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, NULL, NULL, NULL); if (bit_depth < 8) return OPNG_REDUCE_NONE; /* not applicable */ if (color_type & PNG_COLOR_MASK_PALETTE) return OPNG_REDUCE_NONE; /* let opng_reduce_palette() handle it */ byte_depth = bit_depth / 8; channels = png_get_channels(png_ptr, info_ptr); sample_size = channels * byte_depth; offset_alpha = (channels - 1) * byte_depth; /* Select the applicable reductions. */ reductions &= (OPNG_REDUCE_16_TO_8 | OPNG_REDUCE_RGB_TO_GRAY | OPNG_REDUCE_STRIP_ALPHA); if (bit_depth <= 8) reductions &= ~OPNG_REDUCE_16_TO_8; if (!(color_type & PNG_COLOR_MASK_COLOR)) reductions &= ~OPNG_REDUCE_RGB_TO_GRAY; if (!(color_type & PNG_COLOR_MASK_ALPHA)) reductions &= ~OPNG_REDUCE_STRIP_ALPHA; /* Check if the ancillary information allows these reductions. */ #ifdef PNG_bKGD_SUPPORTED if (png_get_bKGD(png_ptr, info_ptr, &background)) { if (reductions & OPNG_REDUCE_16_TO_8) { if (background->red % 257 != 0 || background->green % 257 != 0 || background->blue % 257 != 0 || background->gray % 257 != 0) reductions &= ~OPNG_REDUCE_16_TO_8; } if (reductions & OPNG_REDUCE_RGB_TO_GRAY) { if (background->red != background->green || background->red != background->blue) reductions &= ~OPNG_REDUCE_RGB_TO_GRAY; } } #endif /* Check for each possible reduction, row by row. */ row_ptr = png_get_rows(png_ptr, info_ptr); for (i = 0; i < height; ++i, ++row_ptr) { if (reductions == OPNG_REDUCE_NONE) return OPNG_REDUCE_NONE; /* no need to go any further */ /* Check if it is possible to reduce the bit depth to 8. */ if (reductions & OPNG_REDUCE_16_TO_8) { component_ptr = *row_ptr; for (j = 0; j < channels * width; ++j, component_ptr += 2) { if (component_ptr[0] != component_ptr[1]) { reductions &= ~OPNG_REDUCE_16_TO_8; break; } } } if (bit_depth == 8) { /* Check if it is possible to reduce rgb --> gray. */ if (reductions & OPNG_REDUCE_RGB_TO_GRAY) { component_ptr = *row_ptr; for (j = 0; j < width; ++j, component_ptr += sample_size) { if (component_ptr[0] != component_ptr[1] || component_ptr[0] != component_ptr[2]) { reductions &= ~OPNG_REDUCE_RGB_TO_GRAY; break; } } } /* Check if it is possible to strip the alpha channel. */ if (reductions & OPNG_REDUCE_STRIP_ALPHA) { component_ptr = *row_ptr + offset_alpha; for (j = 0; j < width; ++j, component_ptr += sample_size) { if (component_ptr[0] != 255) { reductions &= ~OPNG_REDUCE_STRIP_ALPHA; break; } } } } else /* bit_depth == 16 */ { /* Check if it is possible to reduce rgb --> gray. */ if (reductions & OPNG_REDUCE_RGB_TO_GRAY) { component_ptr = *row_ptr; for (j = 0; j < width; ++j, component_ptr += sample_size) { if (component_ptr[0] != component_ptr[2] || component_ptr[0] != component_ptr[4] || component_ptr[1] != component_ptr[3] || component_ptr[1] != component_ptr[5]) { reductions &= ~OPNG_REDUCE_RGB_TO_GRAY; break; } } } /* Check if it is possible to strip the alpha channel. */ if (reductions & OPNG_REDUCE_STRIP_ALPHA) { component_ptr = *row_ptr + offset_alpha; for (j = 0; j < width; ++j, component_ptr += sample_size) { if (component_ptr[0] != 255 || component_ptr[1] != 255) { reductions &= ~OPNG_REDUCE_STRIP_ALPHA; break; } } } } } return reductions; } /* * Reduce the image type to a lower bit depth and color type, * by removing redundant bits. * Possible reductions: 16bpp to 8bpp; RGB to gray; strip alpha. * The parameter reductions indicates the intended reductions. * The function returns the successful reductions. * All reductions are performed in a single step. */ static png_uint_32 /* PRIVATE */ opng_reduce_bits(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions) { png_bytepp row_ptr; png_bytep src_ptr, dest_ptr; png_uint_32 width, height; int interlace_type, compression_type, filter_type; int src_bit_depth, dest_bit_depth; int src_byte_depth, dest_byte_depth; int src_color_type, dest_color_type; int src_channels, dest_channels; int src_sample_size, dest_sample_size; int tran_tbl[8]; png_color_16p trans_color; #ifdef PNG_bKGD_SUPPORTED png_color_16p background; #endif #ifdef PNG_sBIT_SUPPORTED png_color_8p sig_bits; #endif png_uint_32 i, j; int k; opng_debug(1, "in opng_reduce_bits"); /* See which reductions may be performed. */ reductions = opng_analyze_bits(png_ptr, info_ptr, reductions); if (reductions == OPNG_REDUCE_NONE) return OPNG_REDUCE_NONE; /* exit early */ png_get_IHDR(png_ptr, info_ptr, &width, &height, &src_bit_depth, &src_color_type, &interlace_type, &compression_type, &filter_type); /* Compute the new image parameters bit_depth, color_type, etc. */ OPNG_ASSERT(src_bit_depth >= 8); if (reductions & OPNG_REDUCE_16_TO_8) { OPNG_ASSERT(src_bit_depth == 16); dest_bit_depth = 8; } else dest_bit_depth = src_bit_depth; src_byte_depth = src_bit_depth / 8; dest_byte_depth = dest_bit_depth / 8; dest_color_type = src_color_type; if (reductions & OPNG_REDUCE_RGB_TO_GRAY) { OPNG_ASSERT(src_color_type & PNG_COLOR_MASK_COLOR); dest_color_type &= ~PNG_COLOR_MASK_COLOR; } if (reductions & OPNG_REDUCE_STRIP_ALPHA) { OPNG_ASSERT(src_color_type & PNG_COLOR_MASK_ALPHA); dest_color_type &= ~PNG_COLOR_MASK_ALPHA; } src_channels = png_get_channels(png_ptr, info_ptr); dest_channels = ((dest_color_type & PNG_COLOR_MASK_COLOR) ? 3 : 1) + ((dest_color_type & PNG_COLOR_MASK_ALPHA) ? 1 : 0); src_sample_size = src_channels * src_byte_depth; dest_sample_size = dest_channels * dest_byte_depth; /* Pre-compute the intra-sample translation table. */ for (k = 0; k < 4 * dest_byte_depth; ++k) tran_tbl[k] = k * src_bit_depth / dest_bit_depth; /* If rgb --> gray, shift the alpha component two positions to the left. */ if ((reductions & OPNG_REDUCE_RGB_TO_GRAY) && (dest_color_type & PNG_COLOR_MASK_ALPHA)) { tran_tbl[dest_byte_depth] = tran_tbl[3 * dest_byte_depth]; if (dest_byte_depth == 2) tran_tbl[dest_byte_depth + 1] = tran_tbl[3 * dest_byte_depth + 1]; } /* Translate the samples to the new image type. */ OPNG_ASSERT(src_sample_size > dest_sample_size); row_ptr = png_get_rows(png_ptr, info_ptr); for (i = 0; i < height; ++i, ++row_ptr) { src_ptr = dest_ptr = *row_ptr; for (j = 0; j < width; ++j) { for (k = 0; k < dest_sample_size; ++k) dest_ptr[k] = src_ptr[tran_tbl[k]]; src_ptr += src_sample_size; dest_ptr += dest_sample_size; } } /* Update the ancillary information. */ if (png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &trans_color)) { if (reductions & OPNG_REDUCE_16_TO_8) { if (trans_color->red % 257 == 0 && trans_color->green % 257 == 0 && trans_color->blue % 257 == 0 && trans_color->gray % 257 == 0) { trans_color->red &= 255; trans_color->green &= 255; trans_color->blue &= 255; trans_color->gray &= 255; } else { /* 16-bit tRNS in 8-bit samples: all pixels are 100% opaque. */ png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1); png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS); } } if (reductions & OPNG_REDUCE_RGB_TO_GRAY) { if (trans_color->red == trans_color->green || trans_color->red == trans_color->blue) trans_color->gray = trans_color->red; else { /* Non-gray tRNS in grayscale image: all pixels are 100% opaque. */ png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1); png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS); } } } #ifdef PNG_bKGD_SUPPORTED if (png_get_bKGD(png_ptr, info_ptr, &background)) { if (reductions & OPNG_REDUCE_16_TO_8) { background->red &= 255; background->green &= 255; background->blue &= 255; background->gray &= 255; } if (reductions & OPNG_REDUCE_RGB_TO_GRAY) background->gray = background->red; } #endif #ifdef PNG_sBIT_SUPPORTED if (png_get_sBIT(png_ptr, info_ptr, &sig_bits)) { if (reductions & OPNG_REDUCE_16_TO_8) { if (sig_bits->red > 8) sig_bits->red = 8; if (sig_bits->green > 8) sig_bits->green = 8; if (sig_bits->blue > 8) sig_bits->blue = 8; if (sig_bits->gray > 8) sig_bits->gray = 8; if (sig_bits->alpha > 8) sig_bits->alpha = 8; } if (reductions & OPNG_REDUCE_RGB_TO_GRAY) { png_byte max_sig_bits = sig_bits->red; if (max_sig_bits < sig_bits->green) max_sig_bits = sig_bits->green; if (max_sig_bits < sig_bits->blue) max_sig_bits = sig_bits->blue; sig_bits->gray = max_sig_bits; } } #endif /* Update the image information. */ png_set_IHDR(png_ptr, info_ptr, width, height, dest_bit_depth, dest_color_type, interlace_type, compression_type, filter_type); return reductions; } /* * Reduce the bit depth of a palette image to the lowest possible value. * The parameter reductions should contain OPNG_REDUCE_8_TO_4_2_1. * The function returns OPNG_REDUCE_8_TO_4_2_1 if successful. */ static png_uint_32 /* PRIVATE */ opng_reduce_palette_bits(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions) { png_bytepp row_ptr; png_bytep src_sample_ptr, dest_sample_ptr; png_uint_32 width, height; int color_type, interlace_type, compression_type, filter_type; int src_bit_depth, dest_bit_depth; unsigned int src_mask_init, src_mask, src_shift, dest_shift; unsigned int sample, dest_buf; png_colorp palette; int num_palette; png_uint_32 i, j; opng_debug(1, "in opng_reduce_palette_bits"); /* Check if the reduction applies. */ if (!(reductions & OPNG_REDUCE_8_TO_4_2_1)) return OPNG_REDUCE_NONE; png_get_IHDR(png_ptr, info_ptr, &width, &height, &src_bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); if (color_type != PNG_COLOR_TYPE_PALETTE) return OPNG_REDUCE_NONE; if (!png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) num_palette = 0; /* Find the smallest possible bit depth. */ if (num_palette > 16) return OPNG_REDUCE_NONE; else if (num_palette > 4) /* 5 .. 16 entries */ dest_bit_depth = 4; else if (num_palette > 2) /* 3 or 4 entries */ dest_bit_depth = 2; else /* 1 or 2 entries */ { OPNG_ASSERT(num_palette > 0); dest_bit_depth = 1; } if (src_bit_depth <= dest_bit_depth) { OPNG_ASSERT(src_bit_depth == dest_bit_depth); return OPNG_REDUCE_NONE; } /* Iterate through all sample values. */ row_ptr = png_get_rows(png_ptr, info_ptr); if (src_bit_depth == 8) { for (i = 0; i < height; ++i, ++row_ptr) { src_sample_ptr = dest_sample_ptr = *row_ptr; dest_shift = 8; dest_buf = 0; for (j = 0; j < width; ++j) { dest_shift -= dest_bit_depth; if (dest_shift > 0) dest_buf |= *src_sample_ptr << dest_shift; else { *dest_sample_ptr++ = (png_byte)(dest_buf | *src_sample_ptr); dest_shift = 8; dest_buf = 0; } ++src_sample_ptr; } if (dest_shift != 0) *dest_sample_ptr = (png_byte)dest_buf; } } else /* src_bit_depth < 8 */ { src_mask_init = (1 << (8 + src_bit_depth)) - (1 << 8); for (i = 0; i < height; ++i, ++row_ptr) { src_sample_ptr = dest_sample_ptr = *row_ptr; src_shift = dest_shift = 8; src_mask = src_mask_init; dest_buf = 0; for (j = 0; j < width; ++j) { src_shift -= src_bit_depth; src_mask >>= src_bit_depth; sample = (*src_sample_ptr & src_mask) >> src_shift; dest_shift -= dest_bit_depth; if (dest_shift > 0) dest_buf |= sample << dest_shift; else { *dest_sample_ptr++ = (png_byte)(dest_buf | sample); dest_shift = 8; dest_buf = 0; } if (src_shift == 0) { src_shift = 8; src_mask = src_mask_init; ++src_sample_ptr; } } if (dest_shift != 0) *dest_sample_ptr = (png_byte)dest_buf; } } /* Update the image information. */ png_set_IHDR(png_ptr, info_ptr, width, height, dest_bit_depth, color_type, interlace_type, compression_type, filter_type); return OPNG_REDUCE_8_TO_4_2_1; } /* * Reduce the image type from grayscale(+alpha) or RGB(+alpha) to palette, * if possible. * The parameter reductions indicates the intended reductions. * The function returns the successful reductions. */ static png_uint_32 /* PRIVATE */ opng_reduce_to_palette(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions) { png_uint_32 result; png_row_info row_info; png_bytepp row_ptr; png_bytep sample_ptr, alpha_row; png_uint_32 height, width; int color_type, interlace_type, compression_type, filter_type; int src_bit_depth, dest_bit_depth, channels; png_color palette[256]; png_byte trans_alpha[256]; png_color_16p trans_color; int num_palette, num_trans, index; unsigned int gray, red, green, blue, alpha; unsigned int prev_gray, prev_red, prev_green, prev_blue, prev_alpha; #ifdef PNG_bKGD_SUPPORTED png_color_16p background; #endif png_uint_32 i, j; opng_debug(1, "in opng_reduce_to_palette"); png_get_IHDR(png_ptr, info_ptr, &width, &height, &src_bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); if (src_bit_depth != 8) return OPNG_REDUCE_NONE; /* nothing is done in this case */ OPNG_ASSERT(!(color_type & PNG_COLOR_MASK_PALETTE)); row_ptr = png_get_rows(png_ptr, info_ptr); channels = png_get_channels(png_ptr, info_ptr); alpha_row = (png_bytep)png_malloc(png_ptr, width); row_info.width = width; row_info.rowbytes = 0; /* not used */ row_info.color_type = (png_byte)color_type; row_info.bit_depth = (png_byte)src_bit_depth; row_info.channels = (png_byte)channels; row_info.pixel_depth = 0; /* not used */ /* Analyze the possibility of this reduction. */ num_palette = num_trans = 0; trans_color = NULL; png_get_tRNS(png_ptr, info_ptr, NULL, NULL, &trans_color); prev_gray = prev_red = prev_green = prev_blue = prev_alpha = 256; for (i = 0; i < height; ++i, ++row_ptr) { sample_ptr = *row_ptr; opng_get_alpha_row(&row_info, trans_color, *row_ptr, alpha_row); if (color_type & PNG_COLOR_MASK_COLOR) { for (j = 0; j < width; ++j, sample_ptr += channels) { red = sample_ptr[0]; green = sample_ptr[1]; blue = sample_ptr[2]; alpha = alpha_row[j]; /* Check the cache first. */ if (red != prev_red || green != prev_green || blue != prev_blue || alpha != prev_alpha) { prev_red = red; prev_green = green; prev_blue = blue; prev_alpha = alpha; if (opng_insert_palette_entry(palette, &num_palette, trans_alpha, &num_trans, 256, red, green, blue, alpha, &index) < 0) /* overflow */ { OPNG_ASSERT(num_palette < 0); i = height; /* forced exit from outer loop */ break; } } } } else /* grayscale */ { for (j = 0; j < width; ++j, sample_ptr += channels) { gray = sample_ptr[0]; alpha = alpha_row[j]; /* Check the cache first. */ if (gray != prev_gray || alpha != prev_alpha) { prev_gray = gray; prev_alpha = alpha; if (opng_insert_palette_entry(palette, &num_palette, trans_alpha, &num_trans, 256, gray, gray, gray, alpha, &index) < 0) /* overflow */ { OPNG_ASSERT(num_palette < 0); i = height; /* forced exit from outer loop */ break; } } } } } #ifdef PNG_bKGD_SUPPORTED if ((num_palette >= 0) && png_get_bKGD(png_ptr, info_ptr, &background)) { /* bKGD has an alpha-agnostic palette entry. */ if (color_type & PNG_COLOR_MASK_COLOR) { red = background->red; green = background->green; blue = background->blue; } else red = green = blue = background->gray; opng_insert_palette_entry(palette, &num_palette, trans_alpha, &num_trans, 256, red, green, blue, 256, &index); if (index >= 0) background->index = (png_byte)index; } #endif /* Continue only if the uncompressed indexed image (pixels + PLTE + tRNS) * is smaller than the uncompressed RGB(A) image. * Casual overhead (headers, CRCs, etc.) is ignored. * * Compare: * num_pixels * (src_bit_depth * channels - dest_bit_depth) / 8 * vs. * sizeof(PLTE) + sizeof(tRNS) */ if (num_palette >= 0) { OPNG_ASSERT(num_palette > 0 && num_palette <= 256); OPNG_ASSERT(num_trans >= 0 && num_trans <= num_palette); if (num_palette <= 2) dest_bit_depth = 1; else if (num_palette <= 4) dest_bit_depth = 2; else if (num_palette <= 16) dest_bit_depth = 4; else dest_bit_depth = 8; /* Do the comparison in a way that does not cause overflow. */ if (channels * 8 == dest_bit_depth || (3 * num_palette + num_trans) * 8 / (channels * 8 - dest_bit_depth) / width / height >= 1) num_palette = -1; } if (num_palette < 0) /* can't reduce */ { png_free(png_ptr, alpha_row); return OPNG_REDUCE_NONE; } /* Reduce. */ row_ptr = png_get_rows(png_ptr, info_ptr); index = -1; prev_red = prev_green = prev_blue = prev_alpha = (unsigned int)(-1); for (i = 0; i < height; ++i, ++row_ptr) { sample_ptr = *row_ptr; opng_get_alpha_row(&row_info, trans_color, *row_ptr, alpha_row); if (color_type & PNG_COLOR_MASK_COLOR) { for (j = 0; j < width; ++j, sample_ptr += channels) { red = sample_ptr[0]; green = sample_ptr[1]; blue = sample_ptr[2]; alpha = alpha_row[j]; /* Check the cache first. */ if (red != prev_red || green != prev_green || blue != prev_blue || alpha != prev_alpha) { prev_red = red; prev_green = green; prev_blue = blue; prev_alpha = alpha; if (opng_insert_palette_entry(palette, &num_palette, trans_alpha, &num_trans, 256, red, green, blue, alpha, &index) != 0) index = -1; /* this should not happen */ } OPNG_ASSERT(index >= 0); (*row_ptr)[j] = (png_byte)index; } } else /* grayscale */ { for (j = 0; j < width; ++j, sample_ptr += channels) { gray = sample_ptr[0]; alpha = alpha_row[j]; /* Check the cache first. */ if (gray != prev_gray || alpha != prev_alpha) { prev_gray = gray; prev_alpha = alpha; if (opng_insert_palette_entry(palette, &num_palette, trans_alpha, &num_trans, 256, gray, gray, gray, alpha, &index) != 0) index = -1; /* this should not happen */ } OPNG_ASSERT(index >= 0); (*row_ptr)[j] = (png_byte)index; } } } /* Update the image information. */ png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_PALETTE, interlace_type, compression_type, filter_type); png_set_PLTE(png_ptr, info_ptr, palette, num_palette); if (num_trans > 0) png_set_tRNS(png_ptr, info_ptr, trans_alpha, num_trans, NULL); /* bKGD (if present) is automatically updated. */ png_free(png_ptr, alpha_row); result = OPNG_REDUCE_RGB_TO_PALETTE; if (reductions & OPNG_REDUCE_8_TO_4_2_1) result |= opng_reduce_palette_bits(png_ptr, info_ptr, reductions); return result; } /* * Analyze the usage of samples. * The output value usage_map[n] indicates whether the sample n * is used. The usage_map[] array must have 256 entries. * The function requires a valid bit depth between 1 and 8. */ static void /* PRIVATE */ opng_analyze_sample_usage(png_structp png_ptr, png_infop info_ptr, png_bytep usage_map) { png_bytepp row_ptr; png_bytep sample_ptr; png_uint_32 width, height; int bit_depth, init_shift, init_mask, shift, mask; #ifdef PNG_bKGD_SUPPORTED png_color_16p background; #endif png_uint_32 i, j; opng_debug(1, "in opng_analyze_sample_usage"); height = png_get_image_height(png_ptr, info_ptr); width = png_get_image_width(png_ptr, info_ptr); bit_depth = png_get_bit_depth(png_ptr, info_ptr); row_ptr = png_get_rows(png_ptr, info_ptr); /* Initialize the output entries with 0. */ memset(usage_map, 0, 256); /* Iterate through all sample values. */ if (bit_depth == 8) { for (i = 0; i < height; ++i, ++row_ptr) { for (j = 0, sample_ptr = *row_ptr; j < width; ++j, ++sample_ptr) usage_map[*sample_ptr] = 1; } } else { OPNG_ASSERT(bit_depth < 8); init_shift = 8 - bit_depth; init_mask = (1 << 8) - (1 << init_shift); for (i = 0; i < height; ++i, ++row_ptr) { for (j = 0, sample_ptr = *row_ptr; j < width; ++sample_ptr) { mask = init_mask; shift = init_shift; do { usage_map[(*sample_ptr & mask) >> shift] = 1; mask >>= bit_depth; shift -= bit_depth; ++j; } while (mask > 0 && j < width); } } } #ifdef PNG_bKGD_SUPPORTED /* bKGD also counts as a used sample. */ if (png_get_bKGD(png_ptr, info_ptr, &background)) usage_map[background->index] = 1; #endif } /* * Reduce the palette. (Only the fast method is implemented.) * The parameter reductions indicates the intended reductions. * The function returns the successful reductions. */ static png_uint_32 /* PRIVATE */ opng_reduce_palette(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions) { png_uint_32 result; png_colorp palette; png_bytep trans_alpha; png_bytepp row_ptr; png_uint_32 width, height; int bit_depth, color_type, interlace_type, compression_type, filter_type; int num_palette, num_trans; int last_color_index, last_trans_index; png_byte crt_trans_value, last_trans_value; png_byte is_used[256]; png_color_16 gray_trans; int is_gray; #ifdef PNG_bKGD_SUPPORTED png_color_16p background; #endif #ifdef PNG_hIST_SUPPORTED png_uint_16p hist; #endif #ifdef PNG_sBIT_SUPPORTED png_color_8p sig_bits; #endif png_uint_32 i, j; int k; opng_debug(1, "in opng_reduce_palette"); result = OPNG_REDUCE_NONE; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &filter_type); row_ptr = png_get_rows(png_ptr, info_ptr); if (!png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) { palette = NULL; num_palette = 0; } if (!png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, NULL)) { trans_alpha = NULL; num_trans = 0; } else OPNG_ASSERT(trans_alpha != NULL && num_trans > 0); opng_analyze_sample_usage(png_ptr, info_ptr, is_used); /* Palette-to-gray does not work (yet) if the bit depth is below 8. */ is_gray = (reductions & OPNG_REDUCE_PALETTE_TO_GRAY) && (bit_depth == 8); last_color_index = last_trans_index = -1; for (k = 0; k < 256; ++k) { if (!is_used[k]) continue; last_color_index = k; if (k < num_trans && trans_alpha[k] < 255) last_trans_index = k; if (is_gray) if (palette[k].red != palette[k].green || palette[k].red != palette[k].blue) is_gray = 0; } OPNG_ASSERT(last_color_index >= 0); OPNG_ASSERT(last_color_index >= last_trans_index); /* Check the integrity of PLTE and tRNS. */ if (last_color_index >= num_palette) { png_warning(png_ptr, "Too few colors in PLTE"); /* Fix the palette by adding blank entries at the end. */ opng_realloc_PLTE(png_ptr, info_ptr, last_color_index + 1); png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); OPNG_ASSERT(num_palette == last_color_index + 1); result |= OPNG_REDUCE_REPAIR; } if (num_trans > num_palette) { png_warning(png_ptr, "Too many alpha values in tRNS"); /* Transparency will be fixed further below. */ result |= OPNG_REDUCE_REPAIR; } /* Check if tRNS can be reduced to grayscale. */ if (is_gray && last_trans_index >= 0) { gray_trans.gray = palette[last_trans_index].red; last_trans_value = trans_alpha[last_trans_index]; for (k = 0; k <= last_color_index; ++k) { if (!is_used[k]) continue; if (k <= last_trans_index) { crt_trans_value = trans_alpha[k]; /* Cannot reduce if different colors have transparency. */ if (crt_trans_value < 255 && palette[k].red != gray_trans.gray) { is_gray = 0; break; } } else crt_trans_value = 255; /* Cannot reduce if same color has multiple transparency levels. */ if (palette[k].red == gray_trans.gray && crt_trans_value != last_trans_value) { is_gray = 0; break; } } } /* Remove tRNS if it is entirely sterile. */ if (num_trans > 0 && last_trans_index < 0) { num_trans = 0; png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, -1); png_set_invalid(png_ptr, info_ptr, PNG_INFO_tRNS); result |= OPNG_REDUCE_PALETTE_FAST; } if (reductions & OPNG_REDUCE_PALETTE_FAST) { if (num_palette != last_color_index + 1) { /* Reduce PLTE. */ /* hIST is reduced automatically. */ opng_realloc_PLTE(png_ptr, info_ptr, last_color_index + 1); png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette); OPNG_ASSERT(num_palette == last_color_index + 1); result |= OPNG_REDUCE_PALETTE_FAST; } if (num_trans > 0 && num_trans != last_trans_index + 1) { /* Reduce tRNS. */ opng_realloc_tRNS(png_ptr, info_ptr, last_trans_index + 1); png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, NULL); OPNG_ASSERT(num_trans == last_trans_index + 1); result |= OPNG_REDUCE_PALETTE_FAST; } } if (reductions & OPNG_REDUCE_8_TO_4_2_1) { result |= opng_reduce_palette_bits(png_ptr, info_ptr, reductions); /* Refresh the image information. */ bit_depth = png_get_bit_depth(png_ptr, info_ptr); } if ((bit_depth < 8) || !is_gray) return result; /* Reduce palette --> grayscale. */ for (i = 0; i < height; ++i) { for (j = 0; j < width; ++j) row_ptr[i][j] = palette[row_ptr[i][j]].red; } /* Update the ancillary information. */ if (num_trans > 0) png_set_tRNS(png_ptr, info_ptr, NULL, 0, &gray_trans); #ifdef PNG_bKGD_SUPPORTED if (png_get_bKGD(png_ptr, info_ptr, &background)) background->gray = palette[background->index].red; #endif #ifdef PNG_hIST_SUPPORTED if (png_get_hIST(png_ptr, info_ptr, &hist)) { png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, -1); png_set_invalid(png_ptr, info_ptr, PNG_INFO_hIST); } #endif #ifdef PNG_sBIT_SUPPORTED if (png_get_sBIT(png_ptr, info_ptr, &sig_bits)) { png_byte max_sig_bits = sig_bits->red; if (max_sig_bits < sig_bits->green) max_sig_bits = sig_bits->green; if (max_sig_bits < sig_bits->blue) max_sig_bits = sig_bits->blue; sig_bits->gray = max_sig_bits; } #endif /* Update the image information. */ png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_GRAY, interlace_type, compression_type, filter_type); png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, -1); png_set_invalid(png_ptr, info_ptr, PNG_INFO_PLTE); return OPNG_REDUCE_PALETTE_TO_GRAY; /* ignore the former result */ } /* * Reduce the image (bit depth + color type + palette) without * losing any information. The palette (if applicable) and the * image data must be present, e.g., by calling png_set_rows(), * or by loading IDAT. * The parameter reductions indicates the intended reductions. * The function returns the successful reductions. */ png_uint_32 PNGAPI opng_reduce_image(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions) { png_uint_32 result; int color_type; opng_debug(1, "in opng_reduce_image_type"); if (!opng_validate_image(png_ptr, info_ptr)) { png_warning(png_ptr, "Image reduction requires the presence of all critical information"); return OPNG_REDUCE_NONE; } color_type = png_get_color_type(png_ptr, info_ptr); /* The reductions below must be applied in this particular order. */ /* Try to reduce the high bits and color/alpha channels. */ result = opng_reduce_bits(png_ptr, info_ptr, reductions); /* Try to reduce the palette image. */ if (color_type == PNG_COLOR_TYPE_PALETTE && (reductions & (OPNG_REDUCE_PALETTE_TO_GRAY | OPNG_REDUCE_PALETTE_FAST | OPNG_REDUCE_8_TO_4_2_1))) result |= opng_reduce_palette(png_ptr, info_ptr, reductions); /* Try to reduce RGB to palette or grayscale to palette. */ if (((color_type & ~PNG_COLOR_MASK_ALPHA) == PNG_COLOR_TYPE_GRAY && (reductions & OPNG_REDUCE_GRAY_TO_PALETTE)) || ((color_type & ~PNG_COLOR_MASK_ALPHA) == PNG_COLOR_TYPE_RGB && (reductions & OPNG_REDUCE_RGB_TO_PALETTE))) { if (!(result & OPNG_REDUCE_PALETTE_TO_GRAY)) result |= opng_reduce_to_palette(png_ptr, info_ptr, reductions); } return result; } #endif /* OPNG_IMAGE_REDUCTIONS_SUPPORTED */ optipng-0.7.7/src/opngreduc/opngreduc.h000066400000000000000000000062411343170417500201310ustar00rootroot00000000000000/* * opngreduc.h - libpng extension: lossless image reductions. * * Copyright (C) 2003-2014 Cosmin Truta. * This software is distributed under the same licensing and warranty terms * as libpng. */ #ifndef OPNGREDUC_H #define OPNGREDUC_H #include "png.h" #ifdef __cplusplus extern "C" { #endif #ifdef PNG_INFO_IMAGE_SUPPORTED /* * Check if the image information is valid. * The image information is said to be valid if all the required * critical chunk data is present in the png structures. * The function returns 1 if this information is valid, and 0 otherwise. */ int PNGAPI opng_validate_image(png_structp png_ptr, png_infop info_ptr); #endif /* PNG_INFO_IMAGE_SUPPORTED */ #ifndef OPNG_NO_IMAGE_REDUCTIONS #define OPNG_IMAGE_REDUCTIONS_SUPPORTED #endif #ifdef OPNG_IMAGE_REDUCTIONS_SUPPORTED #ifndef PNG_INFO_IMAGE_SUPPORTED #error OPNG_IMAGE_REDUCTIONS_SUPPORTED requires PNG_INFO_IMAGE_SUPPORTED #endif #ifndef PNG_tRNS_SUPPORTED #error OPNG_IMAGE_REDUCTIONS_SUPPORTED requires proper transparency support #endif /* * Reduce the image (bit depth + color type + palette) without * losing any information. The palette (if applicable) and the * image data must be present, e.g., by calling png_set_rows(), * or by loading IDAT. * The parameter reductions indicates the intended reductions. * The function returns the successful reductions. */ png_uint_32 PNGAPI opng_reduce_image(png_structp png_ptr, png_infop info_ptr, png_uint_32 reductions); /* * PNG reduction flags. */ #define OPNG_REDUCE_NONE 0x0000 #define OPNG_REDUCE_16_TO_8 0x0001 /* discard bits 8-15 */ #define OPNG_REDUCE_8_TO_4_2_1 0x0002 /* discard bits 4-7, 2-7 or 1-7 */ #define OPNG_REDUCE_RGB_TO_GRAY 0x0004 /* ...also RGBA to GA */ #define OPNG_REDUCE_STRIP_ALPHA 0x0008 /* ...and create tRNS if needed */ #define OPNG_REDUCE_RGB_TO_PALETTE 0x0010 /* ...also RGBA to palette/tRNS */ #define OPNG_REDUCE_PALETTE_TO_RGB 0x0020 /* TODO */ #define OPNG_REDUCE_GRAY_TO_PALETTE 0x0040 /* ...also GA to palette/tRNS */ #define OPNG_REDUCE_PALETTE_TO_GRAY 0x0080 /* ...also palette/tRNS to GA */ #define OPNG_REDUCE_PALETTE_SLOW 0x0100 /* TODO: remove all sterile entries and reorder PLTE */ #define OPNG_REDUCE_PALETTE_FAST 0x0200 /* remove trailing sterile entries only; do not reorder PLTE */ #define OPNG_REDUCE_METADATA 0x1000 /* TODO */ #define OPNG_REDUCE_REPAIR 0x2000 /* repair broken image data */ #define OPNG_REDUCE_BIT_DEPTH \ (OPNG_REDUCE_16_TO_8 | OPNG_REDUCE_8_TO_4_2_1) #define OPNG_REDUCE_COLOR_TYPE \ (OPNG_REDUCE_RGB_TO_GRAY | OPNG_REDUCE_STRIP_ALPHA | \ OPNG_REDUCE_RGB_TO_PALETTE | OPNG_REDUCE_PALETTE_TO_RGB | \ OPNG_REDUCE_GRAY_TO_PALETTE | OPNG_REDUCE_PALETTE_TO_GRAY) #define OPNG_REDUCE_PALETTE \ (OPNG_REDUCE_PALETTE_SLOW | OPNG_REDUCE_PALETTE_FAST) #define OPNG_REDUCE_ALL \ (OPNG_REDUCE_BIT_DEPTH | OPNG_REDUCE_COLOR_TYPE | \ OPNG_REDUCE_PALETTE | OPNG_REDUCE_METADATA) #endif /* OPNG_IMAGE_REDUCTIONS_SUPPORTED */ #ifdef __cplusplus } /* extern "C" */ #endif #endif /* OPNGREDUC_H */ optipng-0.7.7/src/optipng/000077500000000000000000000000001343170417500154615ustar00rootroot00000000000000optipng-0.7.7/src/optipng/Makefile.in000066400000000000000000000170511343170417500175320ustar00rootroot00000000000000.PHONY: all test check clean distclean install uninstall .PRECIOUS: Makefile .SUFFIXES: .c .o .a prefix = @prefix@ exec_prefix = @exec_prefix@ bindir = @bindir@ mandir = @mandir@ man1dir = @man1dir@ CC = @CC@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ LD = @LD@ LDFLAGS = @LDFLAGS@ MKDIR_P = @MKDIR_P@ CP_FP = @CP_FP@ RM_F = @RM_F@ @USE_SYSTEM_LIBPNG_FALSE@LIB_LIBPNG = @USE_SYSTEM_LIBPNG_TRUE@LIB_LIBPNG = @LIBPNG@ @USE_SYSTEM_ZLIB_FALSE@LIB_ZLIB = @USE_SYSTEM_ZLIB_TRUE@LIB_ZLIB = @LIBZ@ LIBM = @LIBM@ LIBS = @LIBS@ ALL_LIBS = $(LIB_LIBPNG) $(LIB_ZLIB) $(LIBM) $(LIBS) OPTIPNG_DIR = ../optipng CEXCEPT_DIR = ../cexcept OPNGREDUC_DIR = ../opngreduc OPNGREDUC_LIB = libopngreduc.a OPNGREDUC_MK = @OPNGREDUC_MK@ PNGXTERN_DIR = ../pngxtern PNGXTERN_LIB = libpngxtern.a PNGXTERN_MK = @PNGXTERN_MK@ @USE_SYSTEM_LIBPNG_FALSE@LIBPNG_DIR = ../libpng @USE_SYSTEM_LIBPNG_FALSE@LIBPNG_LIB = libpng.a @USE_SYSTEM_LIBPNG_TRUE@LIBPNG_LIB = -lpng @USE_SYSTEM_LIBPNG_FALSE@LIBPNG_MK = @LIBPNG_MK@ @USE_SYSTEM_LIBPNG_FALSE@LIBPNG_MK_DEF = @LIBPNG_MK_DEF@ @USE_SYSTEM_ZLIB_FALSE@ZLIB_DIR = ../zlib @USE_SYSTEM_ZLIB_FALSE@ZLIB_LIB = libz.a @USE_SYSTEM_ZLIB_TRUE@ZLIB_LIB = -lz @USE_SYSTEM_ZLIB_FALSE@ZLIB_MK = @ZLIB_MK@ GIF_DIR = ../gifread GIF_LIB = libgifread.a GIF_MK = @GIF_MK@ PNM_DIR = ../pnmio PNM_LIB = libpnmio.a PNM_MK = @PNM_MK@ TIFF_DIR = ../minitiff TIFF_LIB = libminitiff.a TIFF_MK = @TIFF_MK@ OPTIPNG_OBJS = \ optipng.o \ optim.o \ bitset.o \ ioutil.o \ ratio.o \ wildargs.o @USE_SYSTEM_ZLIB_FALSE@OPTIPNG_DEPLIB_ZLIB = $(ZLIB_DIR)/$(ZLIB_LIB) @USE_SYSTEM_ZLIB_TRUE@OPTIPNG_DEPLIB_ZLIB = @USE_SYSTEM_LIBPNG_FALSE@OPTIPNG_DEPLIB_LIBPNG = $(LIBPNG_DIR)/$(LIBPNG_LIB) @USE_SYSTEM_LIBPNG_TRUE@OPTIPNG_DEPLIB_ZLIB = OPTIPNG_DEPLIBS = \ $(OPNGREDUC_DIR)/$(OPNGREDUC_LIB) \ $(PNGXTERN_DIR)/$(PNGXTERN_LIB) \ $(OPTIPNG_DEPLIB_LIBPNG) \ $(OPTIPNG_DEPLIB_ZLIB) \ $(GIF_DIR)/$(GIF_LIB) \ $(PNM_DIR)/$(PNM_LIB) \ $(TIFF_DIR)/$(TIFF_LIB) @USE_SYSTEM_ZLIB_FALSE@OPTIPNG_DEPINCLUDE_ZLIB = -I$(ZLIB_DIR) @USE_SYSTEM_ZLIB_TRUE@OPTIPNG_DEPINCLUDE_ZLIB = @USE_SYSTEM_LIBPNG_FALSE@OPTIPNG_DEPINCLUDE_LIBPNG = -I$(LIBPNG_DIR) @USE_SYSTEM_LIBPNG_TRUE@OPTIPNG_DEPINCLUDE_LIBPNG = OPTIPNG_DEPINCLUDES = \ -I$(CEXCEPT_DIR) \ $(OPTIPNG_DEPINCLUDE_ZLIB) \ $(OPTIPNG_DEPINCLUDE_LIBPNG) \ -I$(OPNGREDUC_DIR) \ -I$(PNGXTERN_DIR) OPTIPNG_TESTS = \ test/bitset_test$(EXEEXT) \ test/ratio_test$(EXEEXT) OPTIPNG_TESTOBJS = \ test/bitset_test.o \ test/ratio_test.o OPTIPNG_TESTOUT = *.out.png test/*.out all: optipng$(EXEEXT) optipng$(EXEEXT): $(OPTIPNG_OBJS) $(OPTIPNG_DEPLIBS) $(LD) $(LDFLAGS) -o $@ $(OPTIPNG_OBJS) $(OPTIPNG_DEPLIBS) $(ALL_LIBS) .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(OPTIPNG_DEPINCLUDES) -o $@ $< optipng.o: optipng.c optipng.h bitset.h proginfo.h $(OPTIPNG_DEPLIBS) optim.o: optim.c optipng.h bitset.h ioutil.h ratio.h $(OPTIPNG_DEPLIBS) bitset.o: bitset.c bitset.h ioutil.o: ioutil.c ioutil.h ratio.o: ratio.c ratio.h wildargs.o: wildargs.c $(OPNGREDUC_DIR)/$(OPNGREDUC_LIB): \ $(OPTIPNG_DEPLIB_LIBPNG) cd $(OPNGREDUC_DIR) && \ $(MAKE) -f $(OPNGREDUC_MK) $(OPNGREDUC_LIB) && \ cd $(OPTIPNG_DIR) $(PNGXTERN_DIR)/$(PNGXTERN_LIB): \ $(OPTIPNG_DEPLIB_LIBPNG) \ $(GIF_DIR)/$(GIF_LIB) \ $(PNM_DIR)/$(PNM_LIB) \ $(TIFF_DIR)/$(TIFF_LIB) cd $(PNGXTERN_DIR) && \ $(MAKE) -f $(PNGXTERN_MK) $(PNGXTERN_LIB) && \ cd $(OPTIPNG_DIR) $(LIBPNG_DIR)/$(LIBPNG_LIB): \ $(OPTIPNG_DEPLIB_ZLIB) cd $(LIBPNG_DIR) && \ $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) && \ cd $(OPTIPNG_DIR) $(ZLIB_DIR)/$(ZLIB_LIB): cd $(ZLIB_DIR) && \ $(MAKE) -f $(ZLIB_MK) && \ cd $(OPTIPNG_DIR) $(GIF_DIR)/$(GIF_LIB): cd $(GIF_DIR) && \ $(MAKE) -f $(GIF_MK) $(GIF_LIB) && \ cd $(OPTIPNG_DIR) $(PNM_DIR)/$(PNM_LIB): cd $(PNM_DIR) && \ $(MAKE) -f $(PNM_MK) $(PNM_LIB) && \ cd $(OPTIPNG_DIR) $(TIFF_DIR)/$(TIFF_LIB): cd $(TIFF_DIR) && \ $(MAKE) -f $(TIFF_MK) $(TIFF_LIB) && \ cd $(OPTIPNG_DIR) test: local-test test-gifread test-minitiff .PHONY: local-test local-test: optipng$(EXEEXT) $(OPTIPNG_TESTS) -@$(RM_F) pngtest.out.png ./optipng$(EXEEXT) -o1 -q img/pngtest.png -out=pngtest.out.png -@echo optipng ... ok test/bitset_test$(EXEEXT) > test/bitset_test.out -@echo bitset_test ... ok test/ratio_test$(EXEEXT) > test/ratio_test.out -@echo ratio_test ... ok test/bitset_test$(EXEEXT): test/bitset_test.o bitset.o $(LD) $(LDFLAGS) -o $@ \ test/bitset_test.o bitset.o $(LIBS) test/ratio_test$(EXEEXT): test/ratio_test.o ratio.o $(LD) $(LDFLAGS) -o $@ \ test/ratio_test.o ratio.o $(LIBS) test/bitset_test.o: test/bitset_test.c bitset.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o $@ $*.c test/ratio_test.o: test/ratio_test.c ratio.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o $@ $*.c .PHONY: test-gifread test-gifread: cd $(GIF_DIR) && \ $(MAKE) -f $(GIF_MK) test && \ cd $(OPTIPNG_DIR) .PHONY: test-minitiff test-minitiff: cd $(TIFF_DIR) && \ $(MAKE) -f $(TIFF_MK) test && \ cd $(OPTIPNG_DIR) check: test clean: \ local-clean \ clean-opngreduc \ clean-pngxtern-gif-pnm-tiff \ clean-libpng \ clean-zlib .PHONY: local-clean local-clean: -$(RM_F) optipng$(EXEEXT) $(OPTIPNG_OBJS) -$(RM_F) $(OPTIPNG_TESTS) $(OPTIPNG_TESTOBJS) $(OPTIPNG_TESTOUT) .PHONY: clean-opngreduc clean-opngreduc: cd $(OPNGREDUC_DIR) && \ $(MAKE) -f $(OPNGREDUC_MK) clean && \ cd $(OPTIPNG_DIR) .PHONY: clean-pngxtern-gif-pnm-tiff clean-pngxtern-gif-pnm-tiff: cd $(PNGXTERN_DIR) && \ $(MAKE) -f $(PNGXTERN_MK) clean && \ cd $(OPTIPNG_DIR) cd $(GIF_DIR) && \ $(MAKE) -f $(GIF_MK) clean && \ cd $(OPTIPNG_DIR) cd $(PNM_DIR) && \ $(MAKE) -f $(PNM_MK) clean && \ cd $(OPTIPNG_DIR) cd $(TIFF_DIR) && \ $(MAKE) -f $(TIFF_MK) clean && \ cd $(OPTIPNG_DIR) .PHONY: clean-libpng clean-libpng: @USE_SYSTEM_LIBPNG_FALSE@ cd $(LIBPNG_DIR) && \ @USE_SYSTEM_LIBPNG_FALSE@ $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) clean && \ @USE_SYSTEM_LIBPNG_FALSE@ cd $(OPTIPNG_DIR) .PHONY: clean-zlib clean-zlib: @USE_SYSTEM_ZLIB_FALSE@ cd $(ZLIB_DIR) && \ @USE_SYSTEM_ZLIB_FALSE@ $(MAKE) -f $(ZLIB_MK) clean && \ @USE_SYSTEM_ZLIB_FALSE@ cd $(OPTIPNG_DIR) distclean: \ local-distclean \ distclean-opngreduc \ distclean-pngxtern-gif-pnm-tiff \ distclean-libpng \ distclean-zlib .PHONY: local-distclean local-distclean: local-clean -$(RM_F) Makefile cd man && \ $(MAKE) distclean && \ cd .. .PHONY: distclean-opngreduc distclean-opngreduc: cd $(OPNGREDUC_DIR) && \ $(MAKE) -f $(OPNGREDUC_MK) distclean && \ cd $(OPTIPNG_DIR) .PHONY: distclean-pngxtern-gif-pnm-tiff distclean-pngxtern-gif-pnm-tiff: cd $(PNGXTERN_DIR) && \ $(MAKE) -f $(PNGXTERN_MK) distclean && \ cd $(OPTIPNG_DIR) cd $(GIF_DIR) && \ $(MAKE) -f $(GIF_MK) distclean && \ cd $(OPTIPNG_DIR) cd $(PNM_DIR) && \ $(MAKE) -f $(PNM_MK) distclean && \ cd $(OPTIPNG_DIR) cd $(TIFF_DIR) && \ $(MAKE) -f $(TIFF_MK) distclean && \ cd $(OPTIPNG_DIR) .PHONY: distclean-libpng distclean-libpng: @USE_SYSTEM_LIBPNG_FALSE@ cd $(LIBPNG_DIR) && \ @USE_SYSTEM_LIBPNG_FALSE@ $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) @LIBPNG_DISTCLEAN@ && \ @USE_SYSTEM_LIBPNG_FALSE@ @LIBPNG_DISTCLEAN_XCMD@ && \ @USE_SYSTEM_LIBPNG_FALSE@ cd $(OPTIPNG_DIR) .PHONY: distclean-zlib distclean-zlib: @USE_SYSTEM_ZLIB_FALSE@ cd $(ZLIB_DIR) && \ @USE_SYSTEM_ZLIB_FALSE@ $(MAKE) -f $(ZLIB_MK) @ZLIB_DISTCLEAN@ && \ @USE_SYSTEM_ZLIB_FALSE@ cd $(OPTIPNG_DIR) install: optipng$(EXEEXT) $(MKDIR_P) $(DESTDIR)$(bindir) $(MKDIR_P) $(DESTDIR)$(man1dir) -@$(RM_F) $(DESTDIR)$(bindir)/optipng$(EXEEXT) -@$(RM_F) $(DESTDIR)$(man1dir)/optipng.1 $(CP_FP) optipng$(EXEEXT) $(DESTDIR)$(bindir) $(CP_FP) man/optipng.1 $(DESTDIR)$(man1dir) uninstall: -$(RM_F) $(DESTDIR)$(bindir)/optipng$(EXEEXT) -$(RM_F) $(DESTDIR)$(man1dir)/optipng.1 optipng-0.7.7/src/optipng/bitset.c000066400000000000000000000125641343170417500171270ustar00rootroot00000000000000/* * bitset.c * Plain old bitset data type. * * Copyright (C) 2001-2017 Cosmin Truta. * * This software is distributed under the zlib license. * Please see the accompanying LICENSE file. */ #include "bitset.h" #include #include #include /* * Returns the minimum of two given values. */ #define opng__MIN__(a, b) \ ((a) < (b) ? (a) : (b)) /* * Returns the maximum of two given values. */ #define opng__MAX__(a, b) \ ((a) > (b) ? (a) : (b)) /* * Spans the given pointer past the elements that satisfy the given predicate. * E.g., opng__SPAN__(str, isspace) moves str past the leading whitespace. */ #define opng__SPAN__(ptr, predicate) \ { \ while ((predicate)(*(ptr))) \ ++(ptr); \ } /* * Counts the number of elements in a bitset. */ unsigned int opng_bitset_count(opng_bitset_t set) { unsigned int result; /* Apply Wegner's method. */ result = 0; while (set != 0) { set &= (set - 1); ++result; } return result; } /* * Finds the first element in a bitset. */ int opng_bitset_find_first(opng_bitset_t set) { int i; for (i = 0; i <= OPNG_BITSET_ELT_MAX; ++i) { if (opng_bitset_test(set, i)) return i; } return -1; } /* * Finds the next element in a bitset. */ int opng_bitset_find_next(opng_bitset_t set, int elt) { int i; for (i = opng__MAX__(elt, -1) + 1; i <= OPNG_BITSET_ELT_MAX; ++i) { if (opng_bitset_test(set, i)) return i; } return -1; } /* * Finds the last element in a bitset. */ int opng_bitset_find_last(opng_bitset_t set) { int i; for (i = OPNG_BITSET_ELT_MAX; i >= 0; --i) { if (opng_bitset_test(set, i)) return i; } return -1; } /* * Finds the previous element in a bitset. */ int opng_bitset_find_prev(opng_bitset_t set, int elt) { int i; for (i = opng__MIN__(elt, OPNG_BITSET_ELT_MAX + 1) - 1; i >= 0; --i) { if (opng_bitset_test(set, i)) return i; } return -1; } /* * Parses a rangeset string and converts the result to a bitset. */ int opng_strparse_rangeset_to_bitset(opng_bitset_t *out_set, const char *rangeset_str, opng_bitset_t mask_set) { opng_bitset_t result; const char *ptr; int state; int num, num1, num2; int err_invalid, err_range; result = OPNG_BITSET_EMPTY; ptr = rangeset_str; state = 0; err_invalid = err_range = 0; num1 = num2 = -1; for ( ; ; ) { opng__SPAN__(ptr, isspace); switch (state) { case 0: /* "" */ case 2: /* "N-" */ /* Expecting number; go to next state. */ if (*ptr >= '0' && *ptr <= '9') { num = 0; do { num = 10 * num + (*ptr - '0'); if (num > OPNG_BITSET_ELT_MAX) { num = OPNG_BITSET_ELT_MAX; err_range = 1; } ++ptr; } while (*ptr >= '0' && *ptr <= '9'); if (!opng_bitset_test(mask_set, num)) err_range = 1; if (state == 0) num1 = num; num2 = num; ++state; continue; } break; case 1: /* "N" */ /* Expecting range operator; go to next state. */ if (*ptr == '-') { ++ptr; num2 = OPNG_BITSET_ELT_MAX; ++state; continue; } break; } if (state > 0) /* "N", "N-" or "N-N" */ { /* Store the partial result; go to state 0. */ if (num1 <= num2) { opng_bitset_set_range(&result, num1, num2); result &= mask_set; } else { /* Incorrect range operands. */ err_range = 1; } state = 0; } if (*ptr == ',' || *ptr == ';') { /* Separator: continue the loop. */ ++ptr; continue; } else if (*ptr == '-') { /* Unexpected range operator: invalidate and exit the loop. */ err_invalid = 1; break; } else { /* Unexpected character or end of string: exit the loop. */ break; } } opng__SPAN__(ptr, isspace); if (*ptr != '\0') { /* Unexpected trailing character: invalidate. */ err_invalid = 1; } if (err_invalid) { /* Invalid input error. */ #ifdef EINVAL errno = EINVAL; #endif *out_set = OPNG_BITSET_EMPTY; return -1; } else if (err_range) { /* Range error. */ #ifdef ERANGE errno = ERANGE; #endif *out_set = OPNG_BITSET_FULL; return -1; } else { /* Success. */ *out_set = result; return 0; } } /* * Formats a bitset using the rangeset string representation. */ size_t opng_strformat_bitset_as_rangeset(char *out_buf, size_t out_buf_size, opng_bitset_t bitset); /* TODO */ optipng-0.7.7/src/optipng/bitset.h000066400000000000000000000147671343170417500171430ustar00rootroot00000000000000/* * bitset.h * Plain old bitset data type. * * Copyright (C) 2001-2017 Cosmin Truta. * * This software is distributed under the zlib license. * Please see the accompanying LICENSE file. */ #ifndef OPNG_BITSET_H_ #define OPNG_BITSET_H_ #include #include #ifdef __cplusplus extern "C" { #endif /* * The bitset type. */ typedef unsigned int opng_bitset_t; /* * Bitset constants. */ #define OPNG_BITSET_EMPTY 0U #define OPNG_BITSET_FULL (~0U) /* * The size operator (not restricted to opng_bitset_t). */ #define OPNG_BITSIZEOF(object) (sizeof(object) * CHAR_BIT) /* * Bitset element limits. */ enum { OPNG_BITSET_ELT_MIN = 0, OPNG_BITSET_ELT_MAX = (int)(OPNG_BITSIZEOF(opng_bitset_t) - 1) }; /* * Direct bitset access methods. */ #ifdef __cplusplus inline int opng_bitset_test(opng_bitset_t set, int elt) { return (set & (1U << elt)) != 0; } inline void opng_bitset_set(opng_bitset_t *set, int elt) { *set |= (1U << elt); } inline void opng_bitset_reset(opng_bitset_t *set, int elt) { *set &= ~(1U << elt); } inline void opng_bitset_flip(opng_bitset_t *set, int elt) { *set ^= (1U << elt); } inline opng_bitset_t opng_bitset__range__(int start_elt, int stop_elt) { return ((1U << (stop_elt - start_elt) << 1) - 1) << start_elt; } inline int opng_bitset_test_all_in_range(opng_bitset_t set, int start_elt, int stop_elt) { return (start_elt <= stop_elt) ? ((~set & opng_bitset__range__(start_elt, stop_elt)) == 0) : 1; } inline int opng_bitset_test_any_in_range(opng_bitset_t set, int start_elt, int stop_elt) { return (start_elt <= stop_elt) ? ((set & opng_bitset__range__(start_elt, stop_elt)) != 0) : 0; } inline void opng_bitset_set_range(opng_bitset_t *set, int start_elt, int stop_elt) { if (start_elt <= stop_elt) *set |= opng_bitset__range__(start_elt, stop_elt); } inline void opng_bitset_reset_range(opng_bitset_t *set, int start_elt, int stop_elt) { if (start_elt <= stop_elt) *set &= ~opng_bitset__range__(start_elt, stop_elt); } inline void opng_bitset_flip_range(opng_bitset_t *set, int start_elt, int stop_elt) { if (start_elt <= stop_elt) *set ^= opng_bitset__range__(start_elt, stop_elt); } #else /* !__cplusplus */ #define opng_bitset_test(set, elt) \ (((set) & (1U << (elt))) != 0) #define opng_bitset_set(set, elt) \ (*(set) |= (1U << (elt))) #define opng_bitset_reset(set, elt) \ (*(set) &= ~(1U << (elt))) #define opng_bitset_flip(set, elt) \ (*(set) ^= (1U << (elt))) #define opng_bitset__range__(start_elt, stop_elt) \ (((1U << ((stop_elt) - (start_elt)) << 1) - 1) << (start_elt)) #define opng_bitset_test_all_in_range(set, start_elt, stop_elt) \ (((start_elt) <= (stop_elt)) ? \ (~(set) & opng_bitset__range__(start_elt, stop_elt)) == 0 : \ 1) #define opng_bitset_test_any_in_range(set, start_elt, stop_elt) \ (((start_elt) <= (stop_elt)) ? \ ((set) & opng_bitset__range__(start_elt, stop_elt)) != 0 : \ 0) #define opng_bitset_set_range(set, start_elt, stop_elt) \ (*(set) |= ((start_elt) <= (stop_elt)) ? \ opng_bitset__range__(start_elt, stop_elt) : \ 0U) #define opng_bitset_reset_range(set, start_elt, stop_elt) \ (*(set) &= ((start_elt) <= (stop_elt)) ? \ ~opng_bitset__range__(start_elt, stop_elt) : \ ~0U) #define opng_bitset_flip_range(set, start_elt, stop_elt) \ (*(set) ^= ((start_elt) <= (stop_elt)) ? \ opng_bitset__range__(start_elt, stop_elt) : \ 0U) #endif /* __cplusplus */ /* * Counts the number of elements in a bitset. * * The function returns the number of bits set to 1. */ unsigned int opng_bitset_count(opng_bitset_t set); /* * Finds the first element in a bitset. * * The function returns the position of the first bit set to 1, * or -1 if all bits are set to 0. */ int opng_bitset_find_first(opng_bitset_t set); /* * Finds the next element in a bitset. * * The function returns the position of the next bit set to 1, * or -1 if all the following bits are set to 0. */ int opng_bitset_find_next(opng_bitset_t set, int elt); /* * Finds the last element in a bitset. * * The function returns the position of the last bit set to 1, * or -1 if all bits are set to 0. */ int opng_bitset_find_last(opng_bitset_t set); /* * Finds the previous element in a bitset. * * The function returns the position of the previous bit set to 1, * or -1 if all the preceding bits are set to 0. */ int opng_bitset_find_prev(opng_bitset_t set, int elt); /* * Parses a rangeset string and converts the result to a bitset. * * A rangeset string is an arbitrary sequence of non-negative integers ("N") * and ranges ("M-N" or "M-"), represented in base 10, and separated by comma * or semicolon characters. Whitespace is allowed around lexical elements, * and is ignored. * * Here are a few examples, assuming the input mask is 0xffff: * "" => 0000000000000000 * "0" => 0000000000000001 * "0,3,5-7" => 0000000011101001 * "0-3,5,7-" => 1111111110101111 * "7-,5" => 1111111110100000 * "7-7" => 0000000010000000 * "7-5" => 1111111111111111, range error * "99" => 1111111111111111, range error * "1-2-3" => 0000000000000000, invalid input error * * On success, the function sets the output value to the converted bitset. * If the input is well-formed, but contains elements or ranges that are not * representable within the given mask, the function sets errno to ERANGE, * and sets the output value to BITSET_FULL. * If the input is ill-formed, the function sets errno to EINVAL, and sets * the output value to BITSET_EMPTY. * * The function returns 0 on success, or -1 on error. */ int opng_strparse_rangeset_to_bitset(opng_bitset_t *out_set, const char *rangeset_str, opng_bitset_t mask_set); /* * Formats a bitset using the rangeset string representation. * * The function returns the length of the rangeset string representation. * Upon return, if the output buffer is large enough, it shall contain the * rangeset string. Otherwise, the buffer shall remain intact. */ size_t opng_strformat_bitset_as_rangeset(char *out_buf, size_t out_buf_size, opng_bitset_t bitset); /* * TODO: * opng_wcsparse_rangeset_to_bitset * opng_wcsformat_bitset_as_rangeset */ #ifdef __cplusplus } /* extern "C" */ #endif #endif /* OPNG_BITSET_H_ */ optipng-0.7.7/src/optipng/build/000077500000000000000000000000001343170417500165605ustar00rootroot00000000000000optipng-0.7.7/src/optipng/build/bcc32.mk000066400000000000000000000136231343170417500200120ustar00rootroot00000000000000# bcc32.mk # Generated from Makefile.in # Preconfigured for Borland C++ # # Usage: make -f build\bcc32.mk CC = bcc32 CFLAGS = -O2 -d -k- -w CPP = #cpp32 -P- CPPFLAGS = LD = $(CC) LDFLAGS = $(CFLAGS) MKDIR_P = mkdir CP_FP = copy RM_F = del /q LIB_LIBPNG = LIB_ZLIB = LIBM = LIBS = #noeh32.lib ALL_LIBS = $(LIB_LIBPNG) $(LIB_ZLIB) $(LIBM) $(LIBS) OPTIPNG_DIR = ..\optipng CEXCEPT_DIR = ..\cexcept OPNGREDUC_DIR = ..\opngreduc OPNGREDUC_LIB = opngreduc.lib OPNGREDUC_MK = build\bcc32.mk PNGXTERN_DIR = ..\pngxtern PNGXTERN_LIB = pngxtern.lib PNGXTERN_MK = build\bcc32.mk LIBPNG_DIR = ..\libpng LIBPNG_LIB = libpng.lib LIBPNG_MK = scripts\makefile.bc32 LIBPNG_MK_DEF = PNGLIBCONF_H_PREBUILT=pnglibconf.h.optipng ZLIB_DIR = ..\zlib ZLIB_LIB = zlib.lib ZLIB_MK = win32\Makefile.bor GIF_DIR = ..\gifread GIF_LIB = gifread.lib GIF_MK = build\bcc32.mk PNM_DIR = ..\pnmio PNM_LIB = pnmio.lib PNM_MK = build\bcc32.mk TIFF_DIR = ..\minitiff TIFF_LIB = minitiff.lib TIFF_MK = build\bcc32.mk OPTIPNG_OBJS = \ optipng.obj \ optim.obj \ bitset.obj \ ioutil.obj \ ratio.obj \ wildargs.obj OPTIPNG_DEPLIB_ZLIB = $(ZLIB_DIR)\$(ZLIB_LIB) OPTIPNG_DEPLIB_LIBPNG = $(LIBPNG_DIR)\$(LIBPNG_LIB) OPTIPNG_DEPLIBS = \ $(OPNGREDUC_DIR)\$(OPNGREDUC_LIB) \ $(PNGXTERN_DIR)\$(PNGXTERN_LIB) \ $(OPTIPNG_DEPLIB_LIBPNG) \ $(OPTIPNG_DEPLIB_ZLIB) \ $(GIF_DIR)\$(GIF_LIB) \ $(PNM_DIR)\$(PNM_LIB) \ $(TIFF_DIR)\$(TIFF_LIB) OPTIPNG_DEPINCLUDE_ZLIB = -I$(ZLIB_DIR) OPTIPNG_DEPINCLUDE_LIBPNG = -I$(LIBPNG_DIR) OPTIPNG_DEPINCLUDES = \ -I$(CEXCEPT_DIR) \ $(OPTIPNG_DEPINCLUDE_ZLIB) \ $(OPTIPNG_DEPINCLUDE_LIBPNG) \ -I$(OPNGREDUC_DIR) \ -I$(PNGXTERN_DIR) OPTIPNG_TESTS = \ test\bitset_test.exe \ test\ratio_test.exe OPTIPNG_TESTOBJS = \ test\bitset_test.obj \ test\ratio_test.obj OPTIPNG_TESTOUT = *.out.png test\*.out all: optipng.exe optipng.exe: $(OPTIPNG_OBJS) $(OPTIPNG_DEPLIBS) $(LD) $(LDFLAGS) -e$@ $(OPTIPNG_OBJS) $(OPTIPNG_DEPLIBS) $(ALL_LIBS) .c.obj: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(OPTIPNG_DEPINCLUDES) -o$@ $< optipng.obj: optipng.c optipng.h bitset.h proginfo.h $(OPTIPNG_DEPLIBS) optim.obj: optim.c optipng.h bitset.h ioutil.h ratio.h $(OPTIPNG_DEPLIBS) bitset.obj: bitset.c bitset.h ioutil.obj: ioutil.c ioutil.h ratio.obj: ratio.c ratio.h wildargs.obj: wildargs.c $(OPNGREDUC_DIR)\$(OPNGREDUC_LIB): \ $(OPTIPNG_DEPLIB_LIBPNG) cd $(OPNGREDUC_DIR) $(MAKE) -f $(OPNGREDUC_MK) $(OPNGREDUC_LIB) cd $(OPTIPNG_DIR) $(PNGXTERN_DIR)\$(PNGXTERN_LIB): \ $(OPTIPNG_DEPLIB_LIBPNG) \ $(GIF_DIR)\$(GIF_LIB) \ $(PNM_DIR)\$(PNM_LIB) \ $(TIFF_DIR)\$(TIFF_LIB) cd $(PNGXTERN_DIR) $(MAKE) -f $(PNGXTERN_MK) $(PNGXTERN_LIB) cd $(OPTIPNG_DIR) $(LIBPNG_DIR)\$(LIBPNG_LIB): \ $(OPTIPNG_DEPLIB_ZLIB) cd $(LIBPNG_DIR) $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) cd $(OPTIPNG_DIR) $(ZLIB_DIR)\$(ZLIB_LIB): cd $(ZLIB_DIR) $(MAKE) -f $(ZLIB_MK) cd $(OPTIPNG_DIR) $(GIF_DIR)\$(GIF_LIB): cd $(GIF_DIR) $(MAKE) -f $(GIF_MK) $(GIF_LIB) cd $(OPTIPNG_DIR) $(PNM_DIR)\$(PNM_LIB): cd $(PNM_DIR) $(MAKE) -f $(PNM_MK) $(PNM_LIB) cd $(OPTIPNG_DIR) $(TIFF_DIR)\$(TIFF_LIB): cd $(TIFF_DIR) $(MAKE) -f $(TIFF_MK) $(TIFF_LIB) cd $(OPTIPNG_DIR) test: local-test test-gifread test-minitiff local-test: optipng.exe $(OPTIPNG_TESTS) -@$(RM_F) pngtest.out.png .\optipng.exe -o1 -q img\pngtest.png -out=pngtest.out.png -@echo optipng ... ok test\bitset_test.exe > test\bitset_test.out -@echo bitset_test ... ok test\ratio_test.exe > test\ratio_test.out -@echo ratio_test ... ok test\bitset_test.exe: test\bitset_test.obj bitset.obj $(LD) $(LDFLAGS) -e$@ \ test\bitset_test.obj bitset.obj $(LIBS) test\ratio_test.exe: test\ratio_test.obj ratio.obj $(LD) $(LDFLAGS) -e$@ \ test\ratio_test.obj ratio.obj $(LIBS) test\bitset_test.obj: test\bitset_test.c bitset.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o$@ $*.c test\ratio_test.obj: test\ratio_test.c ratio.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o$@ $*.c test-gifread: cd $(GIF_DIR) $(MAKE) -f $(GIF_MK) test cd $(OPTIPNG_DIR) test-minitiff: cd $(TIFF_DIR) $(MAKE) -f $(TIFF_MK) test cd $(OPTIPNG_DIR) check: test clean: \ local-clean \ clean-opngreduc \ clean-pngxtern-gif-pnm-tiff \ clean-libpng \ clean-zlib local-clean: -$(RM_F) optipng.exe $(OPTIPNG_OBJS) -$(RM_F) $(OPTIPNG_TESTS) $(OPTIPNG_TESTOBJS) $(OPTIPNG_TESTOUT) -$(RM_F) *.tds clean-opngreduc: cd $(OPNGREDUC_DIR) $(MAKE) -f $(OPNGREDUC_MK) clean cd $(OPTIPNG_DIR) clean-pngxtern-gif-pnm-tiff: cd $(PNGXTERN_DIR) $(MAKE) -f $(PNGXTERN_MK) clean cd $(OPTIPNG_DIR) cd $(GIF_DIR) $(MAKE) -f $(GIF_MK) clean cd $(OPTIPNG_DIR) cd $(PNM_DIR) $(MAKE) -f $(PNM_MK) clean cd $(OPTIPNG_DIR) cd $(TIFF_DIR) $(MAKE) -f $(TIFF_MK) clean cd $(OPTIPNG_DIR) clean-libpng: cd $(LIBPNG_DIR) $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) clean cd $(OPTIPNG_DIR) clean-zlib: cd $(ZLIB_DIR) $(MAKE) -f $(ZLIB_MK) clean cd $(OPTIPNG_DIR) distclean: \ local-distclean \ distclean-opngreduc \ distclean-pngxtern-gif-pnm-tiff \ distclean-libpng \ distclean-zlib local-distclean: local-clean -$(RM_F) Makefile distclean-opngreduc: cd $(OPNGREDUC_DIR) $(MAKE) -f $(OPNGREDUC_MK) distclean cd $(OPTIPNG_DIR) distclean-pngxtern-gif-pnm-tiff: cd $(PNGXTERN_DIR) $(MAKE) -f $(PNGXTERN_MK) distclean cd $(OPTIPNG_DIR) cd $(GIF_DIR) $(MAKE) -f $(GIF_MK) distclean cd $(OPTIPNG_DIR) cd $(PNM_DIR) $(MAKE) -f $(PNM_MK) distclean cd $(OPTIPNG_DIR) cd $(TIFF_DIR) $(MAKE) -f $(TIFF_MK) distclean cd $(OPTIPNG_DIR) distclean-libpng: cd $(LIBPNG_DIR) $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) clean cd $(OPTIPNG_DIR) distclean-zlib: cd $(ZLIB_DIR) $(MAKE) -f $(ZLIB_MK) clean cd $(OPTIPNG_DIR) install: optipng.exe $(MKDIR_P) $(DESTDIR)$(bindir) $(MKDIR_P) $(DESTDIR)$(man1dir) -@$(RM_F) $(DESTDIR)$(bindir)\optipng.exe -@$(RM_F) $(DESTDIR)$(man1dir)\optipng.1 $(CP_FP) optipng.exe $(DESTDIR)$(bindir) $(CP_FP) man\optipng.1 $(DESTDIR)$(man1dir) uninstall: -$(RM_F) $(DESTDIR)$(bindir)\optipng.exe -$(RM_F) $(DESTDIR)$(man1dir)\optipng.1 optipng-0.7.7/src/optipng/build/clang.mk000066400000000000000000000155541343170417500202070ustar00rootroot00000000000000# clang.mk # Generated from Makefile.in # Preconfigured for clang # # Usage: make -f build/clang.mk .PHONY: all test check clean distclean install uninstall .PRECIOUS: Makefile .SUFFIXES: .c .o .a prefix = /usr/local exec_prefix = $(prefix) bindir = $(exec_prefix)/bin mandir = $(prefix)/man man1dir = $(mandir)/man1 CC = clang CFLAGS = -O2 -Wall -Wextra CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s MKDIR_P = mkdir -p CP_FP = cp -f -p RM_F = rm -f LIB_LIBPNG = #LIB_LIBPNG = -lpng LIB_ZLIB = #LIB_ZLIB = -lz LIBM = -lm LIBS = ALL_LIBS = $(LIB_LIBPNG) $(LIB_ZLIB) $(LIBM) $(LIBS) OPTIPNG_DIR = ../optipng CEXCEPT_DIR = ../cexcept OPNGREDUC_DIR = ../opngreduc OPNGREDUC_LIB = libopngreduc.a OPNGREDUC_MK = build/clang.mk PNGXTERN_DIR = ../pngxtern PNGXTERN_LIB = libpngxtern.a PNGXTERN_MK = build/clang.mk LIBPNG_DIR = ../libpng LIBPNG_LIB = libpng.a #LIBPNG_LIB = -lpng LIBPNG_MK = scripts/makefile.gcc LIBPNG_MK_DEF = PNGLIBCONF_H_PREBUILT=pnglibconf.h.optipng ZLIB_DIR = ../zlib ZLIB_LIB = libz.a #ZLIB_LIB = -lz ZLIB_MK = Makefile GIF_DIR = ../gifread GIF_LIB = libgifread.a GIF_MK = build/clang.mk PNM_DIR = ../pnmio PNM_LIB = libpnmio.a PNM_MK = build/clang.mk TIFF_DIR = ../minitiff TIFF_LIB = libminitiff.a TIFF_MK = build/clang.mk OPTIPNG_OBJS = \ optipng.o \ optim.o \ bitset.o \ ioutil.o \ ratio.o \ wildargs.o OPTIPNG_DEPLIB_ZLIB = $(ZLIB_DIR)/$(ZLIB_LIB) #OPTIPNG_DEPLIB_ZLIB = OPTIPNG_DEPLIB_LIBPNG = $(LIBPNG_DIR)/$(LIBPNG_LIB) #OPTIPNG_DEPLIB_ZLIB = OPTIPNG_DEPLIBS = \ $(OPNGREDUC_DIR)/$(OPNGREDUC_LIB) \ $(PNGXTERN_DIR)/$(PNGXTERN_LIB) \ $(OPTIPNG_DEPLIB_LIBPNG) \ $(OPTIPNG_DEPLIB_ZLIB) \ $(GIF_DIR)/$(GIF_LIB) \ $(PNM_DIR)/$(PNM_LIB) \ $(TIFF_DIR)/$(TIFF_LIB) OPTIPNG_DEPINCLUDE_ZLIB = -I$(ZLIB_DIR) #OPTIPNG_DEPINCLUDE_ZLIB = OPTIPNG_DEPINCLUDE_LIBPNG = -I$(LIBPNG_DIR) #OPTIPNG_DEPINCLUDE_LIBPNG = OPTIPNG_DEPINCLUDES = \ -I$(CEXCEPT_DIR) \ $(OPTIPNG_DEPINCLUDE_ZLIB) \ $(OPTIPNG_DEPINCLUDE_LIBPNG) \ -I$(OPNGREDUC_DIR) \ -I$(PNGXTERN_DIR) OPTIPNG_TESTS = \ test/bitset_test$(EXEEXT) \ test/ratio_test$(EXEEXT) OPTIPNG_TESTOBJS = \ test/bitset_test.o \ test/ratio_test.o OPTIPNG_TESTOUT = *.out.png test/*.out all: optipng$(EXEEXT) optipng$(EXEEXT): $(OPTIPNG_OBJS) $(OPTIPNG_DEPLIBS) $(LD) $(LDFLAGS) -o $@ $(OPTIPNG_OBJS) $(OPTIPNG_DEPLIBS) $(ALL_LIBS) .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(OPTIPNG_DEPINCLUDES) -o $@ $< optipng.o: optipng.c optipng.h bitset.h proginfo.h $(OPTIPNG_DEPLIBS) optim.o: optim.c optipng.h bitset.h ioutil.h ratio.h $(OPTIPNG_DEPLIBS) bitset.o: bitset.c bitset.h ioutil.o: ioutil.c ioutil.h ratio.o: ratio.c ratio.h wildargs.o: wildargs.c $(OPNGREDUC_DIR)/$(OPNGREDUC_LIB): \ $(OPTIPNG_DEPLIB_LIBPNG) cd $(OPNGREDUC_DIR) && \ $(MAKE) -f $(OPNGREDUC_MK) $(OPNGREDUC_LIB) && \ cd $(OPTIPNG_DIR) $(PNGXTERN_DIR)/$(PNGXTERN_LIB): \ $(OPTIPNG_DEPLIB_LIBPNG) \ $(GIF_DIR)/$(GIF_LIB) \ $(PNM_DIR)/$(PNM_LIB) \ $(TIFF_DIR)/$(TIFF_LIB) cd $(PNGXTERN_DIR) && \ $(MAKE) -f $(PNGXTERN_MK) $(PNGXTERN_LIB) && \ cd $(OPTIPNG_DIR) $(LIBPNG_DIR)/$(LIBPNG_LIB): \ $(OPTIPNG_DEPLIB_ZLIB) cd $(LIBPNG_DIR) && \ $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) && \ cd $(OPTIPNG_DIR) $(ZLIB_DIR)/$(ZLIB_LIB): cd $(ZLIB_DIR) && \ $(MAKE) -f $(ZLIB_MK) && \ cd $(OPTIPNG_DIR) $(GIF_DIR)/$(GIF_LIB): cd $(GIF_DIR) && \ $(MAKE) -f $(GIF_MK) $(GIF_LIB) && \ cd $(OPTIPNG_DIR) $(PNM_DIR)/$(PNM_LIB): cd $(PNM_DIR) && \ $(MAKE) -f $(PNM_MK) $(PNM_LIB) && \ cd $(OPTIPNG_DIR) $(TIFF_DIR)/$(TIFF_LIB): cd $(TIFF_DIR) && \ $(MAKE) -f $(TIFF_MK) $(TIFF_LIB) && \ cd $(OPTIPNG_DIR) test: local-test test-gifread test-minitiff .PHONY: local-test local-test: optipng$(EXEEXT) $(OPTIPNG_TESTS) -@$(RM_F) pngtest.out.png ./optipng$(EXEEXT) -o1 -q img/pngtest.png -out=pngtest.out.png -@echo optipng ... ok test/bitset_test$(EXEEXT) > test/bitset_test.out -@echo bitset_test ... ok test/ratio_test$(EXEEXT) > test/ratio_test.out -@echo ratio_test ... ok test/bitset_test$(EXEEXT): test/bitset_test.o bitset.o $(LD) $(LDFLAGS) -o $@ \ test/bitset_test.o bitset.o $(LIBS) test/ratio_test$(EXEEXT): test/ratio_test.o ratio.o $(LD) $(LDFLAGS) -o $@ \ test/ratio_test.o ratio.o $(LIBS) test/bitset_test.o: test/bitset_test.c bitset.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o $@ $*.c test/ratio_test.o: test/ratio_test.c ratio.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o $@ $*.c .PHONY: test-gifread test-gifread: cd $(GIF_DIR) && \ $(MAKE) -f $(GIF_MK) test && \ cd $(OPTIPNG_DIR) .PHONY: test-minitiff test-minitiff: cd $(TIFF_DIR) && \ $(MAKE) -f $(TIFF_MK) test && \ cd $(OPTIPNG_DIR) check: test clean: \ local-clean \ clean-opngreduc \ clean-pngxtern-gif-pnm-tiff \ clean-libpng \ clean-zlib .PHONY: local-clean local-clean: -$(RM_F) optipng$(EXEEXT) $(OPTIPNG_OBJS) -$(RM_F) $(OPTIPNG_TESTS) $(OPTIPNG_TESTOBJS) $(OPTIPNG_TESTOUT) .PHONY: clean-opngreduc clean-opngreduc: cd $(OPNGREDUC_DIR) && \ $(MAKE) -f $(OPNGREDUC_MK) clean && \ cd $(OPTIPNG_DIR) .PHONY: clean-pngxtern-gif-pnm-tiff clean-pngxtern-gif-pnm-tiff: cd $(PNGXTERN_DIR) && \ $(MAKE) -f $(PNGXTERN_MK) clean && \ cd $(OPTIPNG_DIR) cd $(GIF_DIR) && \ $(MAKE) -f $(GIF_MK) clean && \ cd $(OPTIPNG_DIR) cd $(PNM_DIR) && \ $(MAKE) -f $(PNM_MK) clean && \ cd $(OPTIPNG_DIR) cd $(TIFF_DIR) && \ $(MAKE) -f $(TIFF_MK) clean && \ cd $(OPTIPNG_DIR) .PHONY: clean-libpng clean-libpng: cd $(LIBPNG_DIR) && \ $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) clean && \ cd $(OPTIPNG_DIR) .PHONY: clean-zlib clean-zlib: cd $(ZLIB_DIR) && \ $(MAKE) -f $(ZLIB_MK) clean && \ cd $(OPTIPNG_DIR) distclean: \ local-distclean \ distclean-opngreduc \ distclean-pngxtern-gif-pnm-tiff \ distclean-libpng \ distclean-zlib .PHONY: local-distclean local-distclean: local-clean -$(RM_F) Makefile cd man && \ $(MAKE) distclean && \ cd .. .PHONY: distclean-opngreduc distclean-opngreduc: cd $(OPNGREDUC_DIR) && \ $(MAKE) -f $(OPNGREDUC_MK) distclean && \ cd $(OPTIPNG_DIR) .PHONY: distclean-pngxtern-gif-pnm-tiff distclean-pngxtern-gif-pnm-tiff: cd $(PNGXTERN_DIR) && \ $(MAKE) -f $(PNGXTERN_MK) distclean && \ cd $(OPTIPNG_DIR) cd $(GIF_DIR) && \ $(MAKE) -f $(GIF_MK) distclean && \ cd $(OPTIPNG_DIR) cd $(PNM_DIR) && \ $(MAKE) -f $(PNM_MK) distclean && \ cd $(OPTIPNG_DIR) cd $(TIFF_DIR) && \ $(MAKE) -f $(TIFF_MK) distclean && \ cd $(OPTIPNG_DIR) .PHONY: distclean-libpng distclean-libpng: cd $(LIBPNG_DIR) && \ $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) clean && \ cd $(OPTIPNG_DIR) .PHONY: distclean-zlib distclean-zlib: cd $(ZLIB_DIR) && \ $(MAKE) -f $(ZLIB_MK) distclean && \ cd $(OPTIPNG_DIR) install: optipng$(EXEEXT) $(MKDIR_P) $(DESTDIR)$(bindir) $(MKDIR_P) $(DESTDIR)$(man1dir) -@$(RM_F) $(DESTDIR)$(bindir)/optipng$(EXEEXT) -@$(RM_F) $(DESTDIR)$(man1dir)/optipng.1 $(CP_FP) optipng$(EXEEXT) $(DESTDIR)$(bindir) $(CP_FP) man/optipng.1 $(DESTDIR)$(man1dir) uninstall: -$(RM_F) $(DESTDIR)$(bindir)/optipng$(EXEEXT) -$(RM_F) $(DESTDIR)$(man1dir)/optipng.1 optipng-0.7.7/src/optipng/build/gcc.mk000066400000000000000000000155321343170417500176530ustar00rootroot00000000000000# gcc.mk # Generated from Makefile.in # Preconfigured for gcc # # Usage: make -f build/gcc.mk .PHONY: all test check clean distclean install uninstall .PRECIOUS: Makefile .SUFFIXES: .c .o .a prefix = /usr/local exec_prefix = $(prefix) bindir = $(exec_prefix)/bin mandir = $(prefix)/man man1dir = $(mandir)/man1 CC = gcc CFLAGS = -O2 -Wall -Wextra CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s MKDIR_P = mkdir -p CP_FP = cp -f -p RM_F = rm -f LIB_LIBPNG = #LIB_LIBPNG = -lpng LIB_ZLIB = #LIB_ZLIB = -lz LIBM = -lm LIBS = ALL_LIBS = $(LIB_LIBPNG) $(LIB_ZLIB) $(LIBM) $(LIBS) OPTIPNG_DIR = ../optipng CEXCEPT_DIR = ../cexcept OPNGREDUC_DIR = ../opngreduc OPNGREDUC_LIB = libopngreduc.a OPNGREDUC_MK = build/gcc.mk PNGXTERN_DIR = ../pngxtern PNGXTERN_LIB = libpngxtern.a PNGXTERN_MK = build/gcc.mk LIBPNG_DIR = ../libpng LIBPNG_LIB = libpng.a #LIBPNG_LIB = -lpng LIBPNG_MK = scripts/makefile.gcc LIBPNG_MK_DEF = PNGLIBCONF_H_PREBUILT=pnglibconf.h.optipng ZLIB_DIR = ../zlib ZLIB_LIB = libz.a #ZLIB_LIB = -lz ZLIB_MK = Makefile GIF_DIR = ../gifread GIF_LIB = libgifread.a GIF_MK = build/gcc.mk PNM_DIR = ../pnmio PNM_LIB = libpnmio.a PNM_MK = build/gcc.mk TIFF_DIR = ../minitiff TIFF_LIB = libminitiff.a TIFF_MK = build/gcc.mk OPTIPNG_OBJS = \ optipng.o \ optim.o \ bitset.o \ ioutil.o \ ratio.o \ wildargs.o OPTIPNG_DEPLIB_ZLIB = $(ZLIB_DIR)/$(ZLIB_LIB) #OPTIPNG_DEPLIB_ZLIB = OPTIPNG_DEPLIB_LIBPNG = $(LIBPNG_DIR)/$(LIBPNG_LIB) #OPTIPNG_DEPLIB_ZLIB = OPTIPNG_DEPLIBS = \ $(OPNGREDUC_DIR)/$(OPNGREDUC_LIB) \ $(PNGXTERN_DIR)/$(PNGXTERN_LIB) \ $(OPTIPNG_DEPLIB_LIBPNG) \ $(OPTIPNG_DEPLIB_ZLIB) \ $(GIF_DIR)/$(GIF_LIB) \ $(PNM_DIR)/$(PNM_LIB) \ $(TIFF_DIR)/$(TIFF_LIB) OPTIPNG_DEPINCLUDE_ZLIB = -I$(ZLIB_DIR) #OPTIPNG_DEPINCLUDE_ZLIB = OPTIPNG_DEPINCLUDE_LIBPNG = -I$(LIBPNG_DIR) #OPTIPNG_DEPINCLUDE_LIBPNG = OPTIPNG_DEPINCLUDES = \ -I$(CEXCEPT_DIR) \ $(OPTIPNG_DEPINCLUDE_ZLIB) \ $(OPTIPNG_DEPINCLUDE_LIBPNG) \ -I$(OPNGREDUC_DIR) \ -I$(PNGXTERN_DIR) OPTIPNG_TESTS = \ test/bitset_test$(EXEEXT) \ test/ratio_test$(EXEEXT) OPTIPNG_TESTOBJS = \ test/bitset_test.o \ test/ratio_test.o OPTIPNG_TESTOUT = *.out.png test/*.out all: optipng$(EXEEXT) optipng$(EXEEXT): $(OPTIPNG_OBJS) $(OPTIPNG_DEPLIBS) $(LD) $(LDFLAGS) -o $@ $(OPTIPNG_OBJS) $(OPTIPNG_DEPLIBS) $(ALL_LIBS) .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(OPTIPNG_DEPINCLUDES) -o $@ $< optipng.o: optipng.c optipng.h bitset.h proginfo.h $(OPTIPNG_DEPLIBS) optim.o: optim.c optipng.h bitset.h ioutil.h ratio.h $(OPTIPNG_DEPLIBS) bitset.o: bitset.c bitset.h ioutil.o: ioutil.c ioutil.h ratio.o: ratio.c ratio.h wildargs.o: wildargs.c $(OPNGREDUC_DIR)/$(OPNGREDUC_LIB): \ $(OPTIPNG_DEPLIB_LIBPNG) cd $(OPNGREDUC_DIR) && \ $(MAKE) -f $(OPNGREDUC_MK) $(OPNGREDUC_LIB) && \ cd $(OPTIPNG_DIR) $(PNGXTERN_DIR)/$(PNGXTERN_LIB): \ $(OPTIPNG_DEPLIB_LIBPNG) \ $(GIF_DIR)/$(GIF_LIB) \ $(PNM_DIR)/$(PNM_LIB) \ $(TIFF_DIR)/$(TIFF_LIB) cd $(PNGXTERN_DIR) && \ $(MAKE) -f $(PNGXTERN_MK) $(PNGXTERN_LIB) && \ cd $(OPTIPNG_DIR) $(LIBPNG_DIR)/$(LIBPNG_LIB): \ $(OPTIPNG_DEPLIB_ZLIB) cd $(LIBPNG_DIR) && \ $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) && \ cd $(OPTIPNG_DIR) $(ZLIB_DIR)/$(ZLIB_LIB): cd $(ZLIB_DIR) && \ $(MAKE) -f $(ZLIB_MK) && \ cd $(OPTIPNG_DIR) $(GIF_DIR)/$(GIF_LIB): cd $(GIF_DIR) && \ $(MAKE) -f $(GIF_MK) $(GIF_LIB) && \ cd $(OPTIPNG_DIR) $(PNM_DIR)/$(PNM_LIB): cd $(PNM_DIR) && \ $(MAKE) -f $(PNM_MK) $(PNM_LIB) && \ cd $(OPTIPNG_DIR) $(TIFF_DIR)/$(TIFF_LIB): cd $(TIFF_DIR) && \ $(MAKE) -f $(TIFF_MK) $(TIFF_LIB) && \ cd $(OPTIPNG_DIR) test: local-test test-gifread test-minitiff .PHONY: local-test local-test: optipng$(EXEEXT) $(OPTIPNG_TESTS) -@$(RM_F) pngtest.out.png ./optipng$(EXEEXT) -o1 -q img/pngtest.png -out=pngtest.out.png -@echo optipng ... ok test/bitset_test$(EXEEXT) > test/bitset_test.out -@echo bitset_test ... ok test/ratio_test$(EXEEXT) > test/ratio_test.out -@echo ratio_test ... ok test/bitset_test$(EXEEXT): test/bitset_test.o bitset.o $(LD) $(LDFLAGS) -o $@ \ test/bitset_test.o bitset.o $(LIBS) test/ratio_test$(EXEEXT): test/ratio_test.o ratio.o $(LD) $(LDFLAGS) -o $@ \ test/ratio_test.o ratio.o $(LIBS) test/bitset_test.o: test/bitset_test.c bitset.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o $@ $*.c test/ratio_test.o: test/ratio_test.c ratio.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o $@ $*.c .PHONY: test-gifread test-gifread: cd $(GIF_DIR) && \ $(MAKE) -f $(GIF_MK) test && \ cd $(OPTIPNG_DIR) .PHONY: test-minitiff test-minitiff: cd $(TIFF_DIR) && \ $(MAKE) -f $(TIFF_MK) test && \ cd $(OPTIPNG_DIR) check: test clean: \ local-clean \ clean-opngreduc \ clean-pngxtern-gif-pnm-tiff \ clean-libpng \ clean-zlib .PHONY: local-clean local-clean: -$(RM_F) optipng$(EXEEXT) $(OPTIPNG_OBJS) -$(RM_F) $(OPTIPNG_TESTS) $(OPTIPNG_TESTOBJS) $(OPTIPNG_TESTOUT) .PHONY: clean-opngreduc clean-opngreduc: cd $(OPNGREDUC_DIR) && \ $(MAKE) -f $(OPNGREDUC_MK) clean && \ cd $(OPTIPNG_DIR) .PHONY: clean-pngxtern-gif-pnm-tiff clean-pngxtern-gif-pnm-tiff: cd $(PNGXTERN_DIR) && \ $(MAKE) -f $(PNGXTERN_MK) clean && \ cd $(OPTIPNG_DIR) cd $(GIF_DIR) && \ $(MAKE) -f $(GIF_MK) clean && \ cd $(OPTIPNG_DIR) cd $(PNM_DIR) && \ $(MAKE) -f $(PNM_MK) clean && \ cd $(OPTIPNG_DIR) cd $(TIFF_DIR) && \ $(MAKE) -f $(TIFF_MK) clean && \ cd $(OPTIPNG_DIR) .PHONY: clean-libpng clean-libpng: cd $(LIBPNG_DIR) && \ $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) clean && \ cd $(OPTIPNG_DIR) .PHONY: clean-zlib clean-zlib: cd $(ZLIB_DIR) && \ $(MAKE) -f $(ZLIB_MK) clean && \ cd $(OPTIPNG_DIR) distclean: \ local-distclean \ distclean-opngreduc \ distclean-pngxtern-gif-pnm-tiff \ distclean-libpng \ distclean-zlib .PHONY: local-distclean local-distclean: local-clean -$(RM_F) Makefile cd man && \ $(MAKE) distclean && \ cd .. .PHONY: distclean-opngreduc distclean-opngreduc: cd $(OPNGREDUC_DIR) && \ $(MAKE) -f $(OPNGREDUC_MK) distclean && \ cd $(OPTIPNG_DIR) .PHONY: distclean-pngxtern-gif-pnm-tiff distclean-pngxtern-gif-pnm-tiff: cd $(PNGXTERN_DIR) && \ $(MAKE) -f $(PNGXTERN_MK) distclean && \ cd $(OPTIPNG_DIR) cd $(GIF_DIR) && \ $(MAKE) -f $(GIF_MK) distclean && \ cd $(OPTIPNG_DIR) cd $(PNM_DIR) && \ $(MAKE) -f $(PNM_MK) distclean && \ cd $(OPTIPNG_DIR) cd $(TIFF_DIR) && \ $(MAKE) -f $(TIFF_MK) distclean && \ cd $(OPTIPNG_DIR) .PHONY: distclean-libpng distclean-libpng: cd $(LIBPNG_DIR) && \ $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) clean && \ cd $(OPTIPNG_DIR) .PHONY: distclean-zlib distclean-zlib: cd $(ZLIB_DIR) && \ $(MAKE) -f $(ZLIB_MK) distclean && \ cd $(OPTIPNG_DIR) install: optipng$(EXEEXT) $(MKDIR_P) $(DESTDIR)$(bindir) $(MKDIR_P) $(DESTDIR)$(man1dir) -@$(RM_F) $(DESTDIR)$(bindir)/optipng$(EXEEXT) -@$(RM_F) $(DESTDIR)$(man1dir)/optipng.1 $(CP_FP) optipng$(EXEEXT) $(DESTDIR)$(bindir) $(CP_FP) man/optipng.1 $(DESTDIR)$(man1dir) uninstall: -$(RM_F) $(DESTDIR)$(bindir)/optipng$(EXEEXT) -$(RM_F) $(DESTDIR)$(man1dir)/optipng.1 optipng-0.7.7/src/optipng/build/unix.mk000066400000000000000000000155341343170417500201040ustar00rootroot00000000000000# unix.mk # Generated from Makefile.in # Preconfigured for Unix (generic) # # Usage: make -f build/unix.mk .PHONY: all test check clean distclean install uninstall .PRECIOUS: Makefile .SUFFIXES: .c .o .a prefix = /usr/local exec_prefix = $(prefix) bindir = $(exec_prefix)/bin mandir = $(prefix)/man man1dir = $(mandir)/man1 CC = cc CFLAGS = -O CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s MKDIR_P = mkdir -p CP_FP = cp -f -p RM_F = rm -f LIB_LIBPNG = #LIB_LIBPNG = -lpng LIB_ZLIB = #LIB_ZLIB = -lz LIBM = -lm LIBS = ALL_LIBS = $(LIB_LIBPNG) $(LIB_ZLIB) $(LIBM) $(LIBS) OPTIPNG_DIR = ../optipng CEXCEPT_DIR = ../cexcept OPNGREDUC_DIR = ../opngreduc OPNGREDUC_LIB = libopngreduc.a OPNGREDUC_MK = build/unix.mk PNGXTERN_DIR = ../pngxtern PNGXTERN_LIB = libpngxtern.a PNGXTERN_MK = build/unix.mk LIBPNG_DIR = ../libpng LIBPNG_LIB = libpng.a #LIBPNG_LIB = -lpng LIBPNG_MK = scripts/makefile.gcc LIBPNG_MK_DEF = PNGLIBCONF_H_PREBUILT=pnglibconf.h.optipng ZLIB_DIR = ../zlib ZLIB_LIB = libz.a #ZLIB_LIB = -lz ZLIB_MK = Makefile GIF_DIR = ../gifread GIF_LIB = libgifread.a GIF_MK = build/unix.mk PNM_DIR = ../pnmio PNM_LIB = libpnmio.a PNM_MK = build/unix.mk TIFF_DIR = ../minitiff TIFF_LIB = libminitiff.a TIFF_MK = build/unix.mk OPTIPNG_OBJS = \ optipng.o \ optim.o \ bitset.o \ ioutil.o \ ratio.o \ wildargs.o OPTIPNG_DEPLIB_ZLIB = $(ZLIB_DIR)/$(ZLIB_LIB) #OPTIPNG_DEPLIB_ZLIB = OPTIPNG_DEPLIB_LIBPNG = $(LIBPNG_DIR)/$(LIBPNG_LIB) #OPTIPNG_DEPLIB_ZLIB = OPTIPNG_DEPLIBS = \ $(OPNGREDUC_DIR)/$(OPNGREDUC_LIB) \ $(PNGXTERN_DIR)/$(PNGXTERN_LIB) \ $(OPTIPNG_DEPLIB_LIBPNG) \ $(OPTIPNG_DEPLIB_ZLIB) \ $(GIF_DIR)/$(GIF_LIB) \ $(PNM_DIR)/$(PNM_LIB) \ $(TIFF_DIR)/$(TIFF_LIB) OPTIPNG_DEPINCLUDE_ZLIB = -I$(ZLIB_DIR) #OPTIPNG_DEPINCLUDE_ZLIB = OPTIPNG_DEPINCLUDE_LIBPNG = -I$(LIBPNG_DIR) #OPTIPNG_DEPINCLUDE_LIBPNG = OPTIPNG_DEPINCLUDES = \ -I$(CEXCEPT_DIR) \ $(OPTIPNG_DEPINCLUDE_ZLIB) \ $(OPTIPNG_DEPINCLUDE_LIBPNG) \ -I$(OPNGREDUC_DIR) \ -I$(PNGXTERN_DIR) OPTIPNG_TESTS = \ test/bitset_test$(EXEEXT) \ test/ratio_test$(EXEEXT) OPTIPNG_TESTOBJS = \ test/bitset_test.o \ test/ratio_test.o OPTIPNG_TESTOUT = *.out.png test/*.out all: optipng$(EXEEXT) optipng$(EXEEXT): $(OPTIPNG_OBJS) $(OPTIPNG_DEPLIBS) $(LD) $(LDFLAGS) -o $@ $(OPTIPNG_OBJS) $(OPTIPNG_DEPLIBS) $(ALL_LIBS) .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(OPTIPNG_DEPINCLUDES) -o $@ $< optipng.o: optipng.c optipng.h bitset.h proginfo.h $(OPTIPNG_DEPLIBS) optim.o: optim.c optipng.h bitset.h ioutil.h ratio.h $(OPTIPNG_DEPLIBS) bitset.o: bitset.c bitset.h ioutil.o: ioutil.c ioutil.h ratio.o: ratio.c ratio.h wildargs.o: wildargs.c $(OPNGREDUC_DIR)/$(OPNGREDUC_LIB): \ $(OPTIPNG_DEPLIB_LIBPNG) cd $(OPNGREDUC_DIR) && \ $(MAKE) -f $(OPNGREDUC_MK) $(OPNGREDUC_LIB) && \ cd $(OPTIPNG_DIR) $(PNGXTERN_DIR)/$(PNGXTERN_LIB): \ $(OPTIPNG_DEPLIB_LIBPNG) \ $(GIF_DIR)/$(GIF_LIB) \ $(PNM_DIR)/$(PNM_LIB) \ $(TIFF_DIR)/$(TIFF_LIB) cd $(PNGXTERN_DIR) && \ $(MAKE) -f $(PNGXTERN_MK) $(PNGXTERN_LIB) && \ cd $(OPTIPNG_DIR) $(LIBPNG_DIR)/$(LIBPNG_LIB): \ $(OPTIPNG_DEPLIB_ZLIB) cd $(LIBPNG_DIR) && \ $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) && \ cd $(OPTIPNG_DIR) $(ZLIB_DIR)/$(ZLIB_LIB): cd $(ZLIB_DIR) && \ $(MAKE) -f $(ZLIB_MK) && \ cd $(OPTIPNG_DIR) $(GIF_DIR)/$(GIF_LIB): cd $(GIF_DIR) && \ $(MAKE) -f $(GIF_MK) $(GIF_LIB) && \ cd $(OPTIPNG_DIR) $(PNM_DIR)/$(PNM_LIB): cd $(PNM_DIR) && \ $(MAKE) -f $(PNM_MK) $(PNM_LIB) && \ cd $(OPTIPNG_DIR) $(TIFF_DIR)/$(TIFF_LIB): cd $(TIFF_DIR) && \ $(MAKE) -f $(TIFF_MK) $(TIFF_LIB) && \ cd $(OPTIPNG_DIR) test: local-test test-gifread test-minitiff .PHONY: local-test local-test: optipng$(EXEEXT) $(OPTIPNG_TESTS) -@$(RM_F) pngtest.out.png ./optipng$(EXEEXT) -o1 -q img/pngtest.png -out=pngtest.out.png -@echo optipng ... ok test/bitset_test$(EXEEXT) > test/bitset_test.out -@echo bitset_test ... ok test/ratio_test$(EXEEXT) > test/ratio_test.out -@echo ratio_test ... ok test/bitset_test$(EXEEXT): test/bitset_test.o bitset.o $(LD) $(LDFLAGS) -o $@ \ test/bitset_test.o bitset.o $(LIBS) test/ratio_test$(EXEEXT): test/ratio_test.o ratio.o $(LD) $(LDFLAGS) -o $@ \ test/ratio_test.o ratio.o $(LIBS) test/bitset_test.o: test/bitset_test.c bitset.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o $@ $*.c test/ratio_test.o: test/ratio_test.c ratio.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -o $@ $*.c .PHONY: test-gifread test-gifread: cd $(GIF_DIR) && \ $(MAKE) -f $(GIF_MK) test && \ cd $(OPTIPNG_DIR) .PHONY: test-minitiff test-minitiff: cd $(TIFF_DIR) && \ $(MAKE) -f $(TIFF_MK) test && \ cd $(OPTIPNG_DIR) check: test clean: \ local-clean \ clean-opngreduc \ clean-pngxtern-gif-pnm-tiff \ clean-libpng \ clean-zlib .PHONY: local-clean local-clean: -$(RM_F) optipng$(EXEEXT) $(OPTIPNG_OBJS) -$(RM_F) $(OPTIPNG_TESTS) $(OPTIPNG_TESTOBJS) $(OPTIPNG_TESTOUT) .PHONY: clean-opngreduc clean-opngreduc: cd $(OPNGREDUC_DIR) && \ $(MAKE) -f $(OPNGREDUC_MK) clean && \ cd $(OPTIPNG_DIR) .PHONY: clean-pngxtern-gif-pnm-tiff clean-pngxtern-gif-pnm-tiff: cd $(PNGXTERN_DIR) && \ $(MAKE) -f $(PNGXTERN_MK) clean && \ cd $(OPTIPNG_DIR) cd $(GIF_DIR) && \ $(MAKE) -f $(GIF_MK) clean && \ cd $(OPTIPNG_DIR) cd $(PNM_DIR) && \ $(MAKE) -f $(PNM_MK) clean && \ cd $(OPTIPNG_DIR) cd $(TIFF_DIR) && \ $(MAKE) -f $(TIFF_MK) clean && \ cd $(OPTIPNG_DIR) .PHONY: clean-libpng clean-libpng: cd $(LIBPNG_DIR) && \ $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) clean && \ cd $(OPTIPNG_DIR) .PHONY: clean-zlib clean-zlib: cd $(ZLIB_DIR) && \ $(MAKE) -f $(ZLIB_MK) clean && \ cd $(OPTIPNG_DIR) distclean: \ local-distclean \ distclean-opngreduc \ distclean-pngxtern-gif-pnm-tiff \ distclean-libpng \ distclean-zlib .PHONY: local-distclean local-distclean: local-clean -$(RM_F) Makefile cd man && \ $(MAKE) distclean && \ cd .. .PHONY: distclean-opngreduc distclean-opngreduc: cd $(OPNGREDUC_DIR) && \ $(MAKE) -f $(OPNGREDUC_MK) distclean && \ cd $(OPTIPNG_DIR) .PHONY: distclean-pngxtern-gif-pnm-tiff distclean-pngxtern-gif-pnm-tiff: cd $(PNGXTERN_DIR) && \ $(MAKE) -f $(PNGXTERN_MK) distclean && \ cd $(OPTIPNG_DIR) cd $(GIF_DIR) && \ $(MAKE) -f $(GIF_MK) distclean && \ cd $(OPTIPNG_DIR) cd $(PNM_DIR) && \ $(MAKE) -f $(PNM_MK) distclean && \ cd $(OPTIPNG_DIR) cd $(TIFF_DIR) && \ $(MAKE) -f $(TIFF_MK) distclean && \ cd $(OPTIPNG_DIR) .PHONY: distclean-libpng distclean-libpng: cd $(LIBPNG_DIR) && \ $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) clean && \ cd $(OPTIPNG_DIR) .PHONY: distclean-zlib distclean-zlib: cd $(ZLIB_DIR) && \ $(MAKE) -f $(ZLIB_MK) distclean && \ cd $(OPTIPNG_DIR) install: optipng$(EXEEXT) $(MKDIR_P) $(DESTDIR)$(bindir) $(MKDIR_P) $(DESTDIR)$(man1dir) -@$(RM_F) $(DESTDIR)$(bindir)/optipng$(EXEEXT) -@$(RM_F) $(DESTDIR)$(man1dir)/optipng.1 $(CP_FP) optipng$(EXEEXT) $(DESTDIR)$(bindir) $(CP_FP) man/optipng.1 $(DESTDIR)$(man1dir) uninstall: -$(RM_F) $(DESTDIR)$(bindir)/optipng$(EXEEXT) -$(RM_F) $(DESTDIR)$(man1dir)/optipng.1 optipng-0.7.7/src/optipng/build/visualc.mk000066400000000000000000000140771343170417500205700ustar00rootroot00000000000000# visualc.mk # Generated from Makefile.in # Preconfigured for Microsoft Visual C++ # # Usage: nmake -f build\visualc.mk CC = cl -nologo CFLAGS = -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -MD -O2 -W4 CPP = cl -nologo -E CPPFLAGS = LD = link -nologo LDFLAGS = MKDIR_P = mkdir CP_FP = copy RM_F = del /q LIB_LIBPNG = LIB_ZLIB = LIBM = LIBS = ALL_LIBS = $(LIB_LIBPNG) $(LIB_ZLIB) $(LIBM) $(LIBS) OPTIPNG_DIR = ..\optipng CEXCEPT_DIR = ..\cexcept OPNGREDUC_DIR = ..\opngreduc OPNGREDUC_LIB = opngreduc.lib OPNGREDUC_MK = build\visualc.mk PNGXTERN_DIR = ..\pngxtern PNGXTERN_LIB = pngxtern.lib PNGXTERN_MK = build\visualc.mk LIBPNG_DIR = ..\libpng LIBPNG_LIB = libpng.lib LIBPNG_MK = scripts\makefile.vcwin32 LIBPNG_MK_DEF = PNGLIBCONF_H_PREBUILT=pnglibconf.h.optipng ZLIB_DIR = ..\zlib ZLIB_LIB = zlib.lib ZLIB_MK = win32\Makefile.msc GIF_DIR = ..\gifread GIF_LIB = gifread.lib GIF_MK = build\visualc.mk PNM_DIR = ..\pnmio PNM_LIB = pnmio.lib PNM_MK = build\visualc.mk TIFF_DIR = ..\minitiff TIFF_LIB = minitiff.lib TIFF_MK = build\visualc.mk OPTIPNG_OBJS = \ optipng.obj \ optim.obj \ bitset.obj \ ioutil.obj \ ratio.obj \ wildargs.obj OPTIPNG_DEPLIB_ZLIB = $(ZLIB_DIR)\$(ZLIB_LIB) OPTIPNG_DEPLIB_LIBPNG = $(LIBPNG_DIR)\$(LIBPNG_LIB) OPTIPNG_DEPLIBS = \ $(OPNGREDUC_DIR)\$(OPNGREDUC_LIB) \ $(PNGXTERN_DIR)\$(PNGXTERN_LIB) \ $(OPTIPNG_DEPLIB_LIBPNG) \ $(OPTIPNG_DEPLIB_ZLIB) \ $(GIF_DIR)\$(GIF_LIB) \ $(PNM_DIR)\$(PNM_LIB) \ $(TIFF_DIR)\$(TIFF_LIB) OPTIPNG_DEPINCLUDE_ZLIB = -I$(ZLIB_DIR) OPTIPNG_DEPINCLUDE_LIBPNG = -I$(LIBPNG_DIR) OPTIPNG_DEPINCLUDES = \ -I$(CEXCEPT_DIR) \ $(OPTIPNG_DEPINCLUDE_ZLIB) \ $(OPTIPNG_DEPINCLUDE_LIBPNG) \ -I$(OPNGREDUC_DIR) \ -I$(PNGXTERN_DIR) OPTIPNG_TESTS = \ test\bitset_test.exe \ test\ratio_test.exe OPTIPNG_TESTOBJS = \ test\bitset_test.obj \ test\ratio_test.obj OPTIPNG_TESTOUT = *.out.png test\*.out all: optipng.exe optipng.exe: $(OPTIPNG_OBJS) $(OPTIPNG_DEPLIBS) $(LD) $(LDFLAGS) -out:$@ $(OPTIPNG_OBJS) $(OPTIPNG_DEPLIBS) $(ALL_LIBS) .c.obj: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(OPTIPNG_DEPINCLUDES) -Fo$@ $< optipng.obj: optipng.c optipng.h bitset.h proginfo.h $(OPTIPNG_DEPLIBS) optim.obj: optim.c optipng.h bitset.h ioutil.h ratio.h $(OPTIPNG_DEPLIBS) bitset.obj: bitset.c bitset.h ioutil.obj: ioutil.c ioutil.h ratio.obj: ratio.c ratio.h wildargs.obj: wildargs.c $(OPNGREDUC_DIR)\$(OPNGREDUC_LIB): \ $(OPTIPNG_DEPLIB_LIBPNG) cd $(OPNGREDUC_DIR) $(MAKE) -f $(OPNGREDUC_MK) $(OPNGREDUC_LIB) cd $(OPTIPNG_DIR) $(PNGXTERN_DIR)\$(PNGXTERN_LIB): \ $(OPTIPNG_DEPLIB_LIBPNG) \ $(GIF_DIR)\$(GIF_LIB) \ $(PNM_DIR)\$(PNM_LIB) \ $(TIFF_DIR)\$(TIFF_LIB) cd $(PNGXTERN_DIR) $(MAKE) -f $(PNGXTERN_MK) $(PNGXTERN_LIB) cd $(OPTIPNG_DIR) $(LIBPNG_DIR)\$(LIBPNG_LIB): \ $(OPTIPNG_DEPLIB_ZLIB) cd $(LIBPNG_DIR) $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) cd $(OPTIPNG_DIR) $(ZLIB_DIR)\$(ZLIB_LIB): cd $(ZLIB_DIR) $(MAKE) -f $(ZLIB_MK) cd $(OPTIPNG_DIR) $(GIF_DIR)\$(GIF_LIB): cd $(GIF_DIR) $(MAKE) -f $(GIF_MK) $(GIF_LIB) cd $(OPTIPNG_DIR) $(PNM_DIR)\$(PNM_LIB): cd $(PNM_DIR) $(MAKE) -f $(PNM_MK) $(PNM_LIB) cd $(OPTIPNG_DIR) $(TIFF_DIR)\$(TIFF_LIB): cd $(TIFF_DIR) $(MAKE) -f $(TIFF_MK) $(TIFF_LIB) cd $(OPTIPNG_DIR) test: local-test test-gifread test-minitiff local-test: optipng.exe $(OPTIPNG_TESTS) -@$(RM_F) pngtest.out.png .\optipng.exe -o1 -q img\pngtest.png -out=pngtest.out.png -@echo optipng ... ok test\bitset_test.exe > test\bitset_test.out -@echo bitset_test ... ok test\ratio_test.exe > test\ratio_test.out -@echo ratio_test ... ok test\bitset_test.exe: test\bitset_test.obj bitset.obj $(LD) $(LDFLAGS) -out:$@ \ test\bitset_test.obj bitset.obj $(LIBS) test\ratio_test.exe: test\ratio_test.obj ratio.obj $(LD) $(LDFLAGS) -out:$@ \ test\ratio_test.obj ratio.obj $(LIBS) test\bitset_test.obj: test\bitset_test.c bitset.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -Fo$@ $*.c test\ratio_test.obj: test\ratio_test.c ratio.h $(CC) -c -I. $(CPPFLAGS) $(CFLAGS) -Fo$@ $*.c test-gifread: cd $(GIF_DIR) $(MAKE) -f $(GIF_MK) test cd $(OPTIPNG_DIR) test-minitiff: cd $(TIFF_DIR) $(MAKE) -f $(TIFF_MK) test cd $(OPTIPNG_DIR) check: test clean: \ local-clean \ clean-opngreduc \ clean-pngxtern-gif-pnm-tiff \ clean-libpng \ clean-zlib local-clean: -$(RM_F) optipng.exe optipng.exe.manifest $(OPTIPNG_OBJS) -$(RM_F) $(OPTIPNG_TESTS) $(OPTIPNG_TESTOBJS) $(OPTIPNG_TESTOUT) clean-opngreduc: cd $(OPNGREDUC_DIR) $(MAKE) -f $(OPNGREDUC_MK) clean cd $(OPTIPNG_DIR) clean-pngxtern-gif-pnm-tiff: cd $(PNGXTERN_DIR) $(MAKE) -f $(PNGXTERN_MK) clean cd $(OPTIPNG_DIR) cd $(GIF_DIR) $(MAKE) -f $(GIF_MK) clean cd $(OPTIPNG_DIR) cd $(PNM_DIR) $(MAKE) -f $(PNM_MK) clean cd $(OPTIPNG_DIR) cd $(TIFF_DIR) $(MAKE) -f $(TIFF_MK) clean cd $(OPTIPNG_DIR) clean-libpng: cd $(LIBPNG_DIR) $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) clean cd $(OPTIPNG_DIR) clean-zlib: cd $(ZLIB_DIR) $(MAKE) -f $(ZLIB_MK) clean cd $(OPTIPNG_DIR) distclean: \ local-distclean \ distclean-opngreduc \ distclean-pngxtern-gif-pnm-tiff \ distclean-libpng \ distclean-zlib local-distclean: local-clean -$(RM_F) Makefile distclean-opngreduc: cd $(OPNGREDUC_DIR) $(MAKE) -f $(OPNGREDUC_MK) distclean cd $(OPTIPNG_DIR) distclean-pngxtern-gif-pnm-tiff: cd $(PNGXTERN_DIR) $(MAKE) -f $(PNGXTERN_MK) distclean cd $(OPTIPNG_DIR) cd $(GIF_DIR) $(MAKE) -f $(GIF_MK) distclean cd $(OPTIPNG_DIR) cd $(PNM_DIR) $(MAKE) -f $(PNM_MK) distclean cd $(OPTIPNG_DIR) cd $(TIFF_DIR) $(MAKE) -f $(TIFF_MK) distclean cd $(OPTIPNG_DIR) distclean-libpng: cd $(LIBPNG_DIR) $(MAKE) -f $(LIBPNG_MK) $(LIBPNG_MK_DEF) clean cd $(OPTIPNG_DIR) distclean-zlib: cd $(ZLIB_DIR) $(MAKE) -f $(ZLIB_MK) clean cd $(OPTIPNG_DIR) install: optipng.exe $(MKDIR_P) $(DESTDIR)$(bindir) $(MKDIR_P) $(DESTDIR)$(man1dir) -@$(RM_F) $(DESTDIR)$(bindir)\optipng.exe $(DESTDIR)$(bindir)\optipng.exe.manifest -@$(RM_F) $(DESTDIR)$(man1dir)\optipng.1 $(CP_FP) optipng.exe $(DESTDIR)$(bindir) $(CP_FP) man\optipng.1 $(DESTDIR)$(man1dir) uninstall: -$(RM_F) $(DESTDIR)$(bindir)\optipng.exe $(DESTDIR)$(bindir)\optipng.exe.manifest -$(RM_F) $(DESTDIR)$(man1dir)\optipng.1 optipng-0.7.7/src/optipng/img/000077500000000000000000000000001343170417500162355ustar00rootroot00000000000000optipng-0.7.7/src/optipng/img/index.txt000066400000000000000000000000541343170417500201040ustar00rootroot00000000000000pngtest.png: The test image used by libpng. optipng-0.7.7/src/optipng/img/pngtest.png000066400000000000000000000206401343170417500204310ustar00rootroot00000000000000PNG  IHDR[ERgAMA asBITM-bKGD/ oFFs-X,pCALbogus unitsfoo/bar1.0e065.535e3W@{ pHYs  tIME:&z tEXtTitlePNGy5sTER䵜 vpAgdd&^IDATxOhdɝ?9 "2@<RC!kڛ0P}Sͩu:a %Lޡ C7ă*xM!^*UuUwG*3#"!dXϏ+x=hʕ0:yѰg_"<+糲+Iy+Ma JáwĘ~gWU͔B&ˠtU5u-()0u=t>ǣ}{>bѨJ_GoTZ;߭GհWy'gy/_ ˌ|G>ܜy3=9ZO.n6waZvOOVcujX:0Z5?{z:nF]5i:]0tR sHdx~|F@lE۪EAu䓣*Mzt[9Q!")=?>X}r4\<ދ'G =MJPF$#Ć*D3׹sLܭ5-\\:X#eӱ9?>g4F1Z(L\ r@T^t 糲sӳ3..`mn'GըoWUϪ=?y_m(!_}{mk}E,aZ|X䣟ZppK o@p_O W 79&8y0\ͽG:Rٴ|}U'_?zՌz)-dd*Db~m9W>p:)AQ}AXUf*J癔Ub:e5oҿY ~K_8N.0ΏVSWMo nt:|nWKhpaaٳ#"_Y7n wZ k4J`Z:>y*g uid 0w5ۃE"h%>0mB0(%\@A2x6磃O'%.Ԭ`ptM-F`RV0DtH*ݿ5ԝ h&y|K\Չ @droa,LP=_糎f}>LK?ӒouuFqGjig&?I{~4Z*\%[ti`*bxotXXN'e5)S8 )[\:" JDbL9paD[kgÁ}`xz8wɦGizJdt8~A%BMi"r>߷τ,/0/mϼ7֤Hr.}MીQӋ9"Vp*Wv:xMM yzHU""ER]_J*B'}q|$@^:.]>4NJ\CxC<#'%E \ ތJ )N@['D:H,(ͥAa&f]i'SlJ1\ kɕ"n(rEa5|=d 8(rGΦ%jFHDa5Ft#X%O/:W‡:諆q!=`Mz:k1bu }'$H&ICSfWH&XLւF>kEaœcD`cs q{//éN`RD2P"JwzGbCxB:^T ֑WVƻ<{:8AC g3W6?9d ќn;B| QE~|4,NJFO_K~ɨEGP"7DžBgl[ol22%_ ١K˯fUXl}!??*lrE2BL§A٣BgJ=MR-@8fWޞB>,tZ|:uLx;ଅ ؅ył|+M\??&[{Ӹaօ !zփPHjdoȭt~+M*׹sZ 1 LQϮN!nՀHב*F"ٴ|zs4pPt"`條pܱg^?a$'w1#!F : iJ$/N mcdrkZ_YRFȰF|4oՋ N=۟Ֆ:wG+ spP!kΨTܩt}˚hBhpulLƕ(ȣz5L]4uĵl>j/V{LC`+d7&]4=)SN+M5 ׹HLx:cÞ\~hMּ:F$ 1|8(Aa΍cDZtYzbzK- J5Cln|NIzO4$|:ZgX% u :h7NtTc13o0:#2%䢵dLˊ+.NM$r9&IFRFuz1v2crun  =qAegZ4׈@ J ALJSEҵ^mkOQD8!rc_·i&mFe> t)L5LJ2ɍH_ݜc[hdca"wi:D&&kab_֢4kT⺼ %r-D0j(ʖ>UQlǦcF275}g :(FJ{ɕ.Pr|rqy/r\>-Rա|MЫP7ZK{] m#P2eP(Mh/K&KRČJӷU TuF &ee"i >DКT6WJ%B"6D;ʋPXťc^y>;|h0*KzLK4`ڀB2餣,i-X 2N;6vurUT!+j'msEjL&\:O4[%1=ux1lYٙ;_~f*դ{[LI]g<(thp cdm@D|X&塐LMqĦj})rp::Y|CY#=k6i!!dt"B!M}k$>~>3Ƴ'F'^Y=x<뼊ޙna`5>\syq>ķef;U\MrKª7^16nYeS&ucx#Og"o1ǵfԉLj{)3:q#,ˤK_; ϶<{Z֩a5go1W d&6F(}dӋ&nAϪQ0>|zԚA Йp~or._-ڤE~8;yG'ww,?˷\A7}&6Wyjꧬ,悫ZgUAcY7U1F:䲂ؠT8! EYrܫGQ%O=?w'/yv56b".Ȳ._\b-ȪPE[?* <f$ q6-o#U pXdN JdhxȲ̸Emњ+?ɚ?ܷӺ<)jM̛JMVB᠘\%AI{NdJ0ZI@^}KIYqPd ;7?L"=?J5{ffM_ hVBtogyѰg[j$4 ĘP\]Hy$Kv|)Nh؛ W-VHN 's7E^Y-)xӻDFœ=!rY&*\7-7u*COx2wDB}>L[  'GCtb[.FKb~kVwn|jT_ U*Ƕ|[l>63Iq*.r'-jг`/EH֎x},&k0]d"UXg[@˃=ّ]Eb٧@ϭF!6!GN.>0GbZ#OK7rMru8B|zЯh4,u.ˁsUH4E)W~`*t&4ML0"LJX0ٓ:D=K_Gjf^mmI+[,M !Hl 2"osLgW>5t>LC'|ޠ=Ygsf.k&7 ct5 墬eMfUXU JFgyFehg߷D)Aic"=]G 0}kr6Ϊs7CgbjAR5L¦j"HUkzA+zCĴijqU|x:yT};2J#!IM#7wuVoҳT|&gSMpe+6 fYt2gZ|\rOGp2wn ѩLu+s"1vJB$d!3gW.2z, ˍ^7*jS \;?A!"_qv,[&Ǔ%3_XFvhՋT͋"f79n]^FX%gI#h-~_޽ݝ_?zn;]ԋ"._{-^.`w;CtX,rYl֭{vob tkVeڭ1vzNU )ެ5 S&4uHHZH\WոpYƊ5nU:.^#|i c''0(it'Di!}#_ws.[&[!MQ4xw;);6KWeh E7ɅH?U-WDY>FӕPy!P:sڻ<ϬI -WkC7/HcLRd풭q%)+j%}vJP&ԑÁzw4#;ۢ~Gde/j;˗E\"-!%_-Hmw0/p/[vn:ֻ;rv/^FX"[,",B\zw[Zٷ"J$ %6Y2n`Hd2.Y,"c}OlҿDvo\Lto%u1;[*!6dY~!nwZU[lnY–dnori܋Ed[:jKӅeqY~XPVb\~`vM>U=_OZ,K%vw~/_Е--gW,m.[K:㋰lwYҥu[\,%leן˶`Ao aɲL_ݭY{6Np)`$jag 6\]3w55鸭que)UJSL|MMT/|`ZtY_%?ǞUmevuDe[{8`WN7SX,??f߂%įFsO !.ɲ..jA\.ͺ҅7]&_dw[%sOq⽕mvwO:%/_4XD~rg_3_"򙫸(/,Kv[tt,K,;ېLҕ ;/.:-6H/LD_i\.w~dw/)L|]uŬZr ϫ2".{~W.v!,:?tKX-ȎEwnnwIxv._Գ)L3˗ p/t2~WqI!½dwX$wd]6qڂ]Mvâu`_iaq:Weg?K_,j[KU˲ yqSe'_[qDn\vW-|f N2a H%=_/ntɿ?o^~粘Up0]\]3)}8knc(kW?.8Yd#L8]!2mHM2b?}#>. 4&BhȆ@U/L""ۖ?إwƳ]3 2o .6bL$i9ʦ@Ӷ)B! X7՛SɃTG)wȺUF={2ϏS̯IOg&!2x6& G``G"sy>nvpjђ!ԍ^UyI՜Z#\ӹ^K^=4PXçcMJx(!N ݷLj:YWF21% d!e&KG-eW Q;?I~݌-}ܑ S׉#:%s"=K!Db}n޷9==seuoMt27w):W8(X/Z OxT!> W7KWM>!Q ,HA+ ΕzTXtDescriptionxMAJ@}N 3a@N=?IARtUFr{W6j&l(.xC:pk)u#)^ ΈF'1ؖi iYyoL\C-P1qZDmMG"IVbI;Ȧ`A_xHBykLwnW#sIENDB`optipng-0.7.7/src/optipng/ioutil.c000066400000000000000000000443241343170417500171410ustar00rootroot00000000000000/* * ioutil.c * I/O utilities. * * Copyright (C) 2003-2017 Cosmin Truta and the Contributing Authors. * * This software is distributed under the zlib license. * Please see the accompanying LICENSE file. */ #include "ioutil.h" #include #include #include /* * Auto-configuration. */ #if defined UNIX || defined __UNIX__ || defined __unix || defined __unix__ || \ defined _BSD_SOURCE || defined _GNU_SOURCE || defined _SVID_SOURCE || \ defined _POSIX_SOURCE || defined _POSIX_C_SOURCE || defined _XOPEN_SOURCE # define OPNG_OS_UNIX #endif #if defined __APPLE__ && defined __MACH__ # define OPNG_OS_DARWIN # ifndef OPNG_OS_UNIX /* The macros __unix and __unix__ are not predefined on Darwin. */ # define OPNG_OS_UNIX # endif #endif #if defined WIN32 || defined _WIN32 || defined _WIN32_WCE || \ defined __WIN32__ || defined __NT__ # define OPNG_OS_WIN32 #endif #if defined WIN64 || defined _WIN64 || defined __WIN64__ # define OPNG_OS_WIN64 #endif #if defined OPNG_OS_WIN32 || defined OPNG_OS_WIN64 # define OPNG_OS_WINDOWS #endif #if defined DOS || defined _DOS || defined __DOS__ || \ defined MSDOS || defined _MSDOS || defined __MSDOS__ # define OPNG_OS_DOS #endif #if defined OS2 || defined OS_2 || defined __OS2__ # define OPNG_OS_OS2 #endif #if defined OPNG_OS_DOS || defined OPNG_OS_OS2 # define OPNG_OS_DOSISH #endif #if defined __CYGWIN__ || defined __DJGPP__ || defined __EMX__ # define OPNG_OS_UNIXISH # ifndef OPNG_OS_UNIX /* Strictly speaking, this is not correct, but "it works". */ # define OPNG_OS_UNIX # endif #endif #if defined OPNG_OS_UNIX || \ (!defined OPNG_OS_WINDOWS && !defined OPNG_OS_DOSISH) # include # if defined _POSIX_VERSION || defined _XOPEN_VERSION # ifndef OPNG_OS_UNIX # define OPNG_OS_UNIX # endif # endif #endif #if defined OPNG_OS_UNIX || defined OPNG_OS_WINDOWS || defined OPNG_OS_DOSISH # include # include # include # if defined _MSC_VER || defined __WATCOMC__ # include # else # include # endif #endif #if defined OPNG_OS_WINDOWS || \ defined OPNG_OS_DOSISH || defined OPNG_OS_UNIXISH # include #endif #if defined OPNG_OS_WINDOWS # include #endif #if defined OPNG_OS_DOSISH # include #endif /* * More auto-configuration. */ #if (defined OPNG_OS_WINDOWS || defined OPNG_OS_DOSISH) && \ !defined OPNG_OS_UNIXISH # define OPNG_PATH_DIRSEP '\\' # define OPNG_PATH_DIRSEP_STR "\\" # define OPNG_PATH_DIRSEP_ALL_STR "/\\" #else # define OPNG_PATH_DIRSEP '/' # define OPNG_PATH_DIRSEP_STR "/" # if defined OPNG_OS_UNIXISH # define OPNG_PATH_DIRSEP_ALL_STR "/\\" # elif defined OPNG_OS_DARWIN # define OPNG_PATH_DIRSEP_ALL_STR "/:" # else /* OPNG_OS_UNIX and others */ # define OPNG_PATH_DIRSEP_ALL_STR "/" # endif #endif #define OPNG_PATH_EXTSEP '.' #define OPNG_PATH_EXTSEP_STR "." #if defined OPNG_OS_WINDOWS || \ defined OPNG_OS_DOSISH || defined OPNG_OS_UNIXISH # define OPNG_PATH_DOS #endif #ifdef R_OK # define OPNG_TEST_READ R_OK #else # define OPNG_TEST_READ 4 #endif #ifdef W_OK # define OPNG_TEST_WRITE W_OK #else # define OPNG_TEST_WRITE 2 #endif #ifdef X_OK # define OPNG_TEST_EXEC X_OK #else # define OPNG_TEST_EXEC 1 #endif #ifdef F_OK # define OPNG_TEST_FILE F_OK #else # define OPNG_TEST_FILE 0 #endif /* * Utility macros. */ #ifdef OPNG_PATH_DOS # define OPNG_PATH_IS_DRIVE_LETTER(ch) \ (((ch) >= 'A' && (ch) <= 'Z') || ((ch) >= 'a' && (ch) <= 'z')) #endif #ifdef OPNG_OS_WINDOWS # if defined OPNG_OS_WIN64 || (defined _MSC_VER && _MSC_VER >= 1500) # define OPNG_HAVE_STDIO__I64 # define OPNG_OS_WINDOWS_IS_WIN9X() 0 # else # if (defined _MSC_VER && _MSC_VER >= 1400) || \ (defined __MSVCRT_VERSION__ && __MSVCRT_VERSION__ >= 0x800) # define OPNG_HAVE_STDIO__I64 # endif # define OPNG_OS_WINDOWS_IS_WIN9X() (GetVersion() >= 0x80000000U) # endif #endif /* * Returns the current value of the file position indicator. */ opng_foffset_t opng_ftello(FILE *stream) { #if defined OPNG_HAVE_STDIO__I64 return (opng_foffset_t)_ftelli64(stream); #elif defined OPNG_OS_UNIX && (OPNG_FOFFSET_MAX > LONG_MAX) /* We don't know if off_t is sufficiently wide, we only know that * long isn't. We are trying just a little harder, in the absence * of an fopen64/ftell64 solution. */ return (opng_foffset_t)ftello(stream); #else /* generic */ return (opng_foffset_t)ftell(stream); #endif } /* * Sets the file position indicator at the specified file offset. */ int opng_fseeko(FILE *stream, opng_foffset_t offset, int whence) { #if defined OPNG_HAVE_STDIO__I64 return _fseeki64(stream, (__int64)offset, whence); #elif defined OPNG_OS_UNIX #if OPNG_FOFFSET_MAX > LONG_MAX /* We don't know if off_t is sufficiently wide, we only know that * long isn't. We are trying just a little harder, in the absence * of an fopen64/fseek64 solution. */ return fseeko(stream, (off_t)offset, whence); #else return fseek(stream, (long)offset, whence); #endif #else /* generic */ return (fseek(stream, (long)offset, whence) == 0) ? 0 : -1; #endif } /* * Reads a block of data from the specified file offset. */ size_t opng_freado(FILE *stream, opng_foffset_t offset, int whence, void *block, size_t blocksize) { fpos_t pos; size_t result; if (fgetpos(stream, &pos) != 0) return 0; if (opng_fseeko(stream, offset, whence) == 0) result = fread(block, 1, blocksize, stream); else result = 0; if (fsetpos(stream, &pos) != 0) result = 0; return result; } /* * Writes a block of data at the specified file offset. */ size_t opng_fwriteo(FILE *stream, opng_foffset_t offset, int whence, const void *block, size_t blocksize) { fpos_t pos; size_t result; if (fgetpos(stream, &pos) != 0 || fflush(stream) != 0) return 0; if (opng_fseeko(stream, offset, whence) == 0) result = fwrite(block, 1, blocksize, stream); else result = 0; if (fflush(stream) != 0) result = 0; if (fsetpos(stream, &pos) != 0) result = 0; return result; } /* * Gets the size of the specified file stream. */ int opng_fgetsize(FILE *stream, opng_fsize_t *size) { #if defined OPNG_OS_WINDOWS HANDLE hFile; DWORD dwSizeLow, dwSizeHigh; hFile = (HANDLE)_get_osfhandle(_fileno(stream)); dwSizeLow = GetFileSize(hFile, &dwSizeHigh); if (GetLastError() != NO_ERROR) return -1; *size = (opng_fsize_t)dwSizeLow + ((opng_fsize_t)dwSizeHigh << 32); return 0; #elif defined OPNG_OS_UNIX struct stat sbuf; if (fstat(fileno(stream), &sbuf) != 0) return -1; if (sbuf.st_size < 0) return -1; *size = (opng_fsize_t)sbuf.st_size; return 0; #else /* generic */ opng_foffset_t offset; if (opng_fseeko(stream, 0, SEEK_END) != 0) return -1; offset = opng_ftello(stream); if (offset < 0) return -1; *size = (opng_fsize_t)offset; return 0; #endif } /* * Makes a new path name by replacing the directory component of * a specified path name. */ char * opng_path_replace_dir(char *buffer, size_t bufsize, const char *old_path, const char *new_dirname) { const char *path, *ptr; size_t dirlen; /* Extract file name from old_path. */ path = old_path; #ifdef OPNG_PATH_DOS /* Skip the drive name, if present. */ if (OPNG_PATH_IS_DRIVE_LETTER(path[0]) && path[1] == ':') path += 2; #endif for ( ; ; ) { ptr = strpbrk(path, OPNG_PATH_DIRSEP_ALL_STR); if (ptr == NULL) break; path = ptr + 1; } /* Make sure the buffer is large enough. */ dirlen = strlen(new_dirname); if (dirlen + strlen(path) + 2 >= bufsize) /* overflow */ return NULL; /* Copy the new directory name. Also append a slash if necessary. */ if (dirlen > 0) { strcpy(buffer, new_dirname); #ifdef OPNG_PATH_DOS if (dirlen == 2 && buffer[1] == ':' && OPNG_PATH_IS_DRIVE_LETTER(buffer[0])) { /* Special case: do not append slash to "C:". */ } else #endif { if (strchr(OPNG_PATH_DIRSEP_ALL_STR, buffer[dirlen - 1]) == NULL) buffer[dirlen++] = OPNG_PATH_DIRSEP; } } /* Append the file name. */ strcpy(buffer + dirlen, path); return buffer; } /* * Makes a new path name by changing the extension component of * a specified path name. */ char * opng_path_replace_ext(char *buffer, size_t bufsize, const char *old_path, const char *new_extname) { size_t i, pos; if (new_extname[0] != OPNG_PATH_EXTSEP) /* invalid argument */ return NULL; for (i = 0, pos = (size_t)(-1); old_path[i] != '\0'; ++i) { if (i >= bufsize) /* overflow */ return NULL; if ((buffer[i] = old_path[i]) == OPNG_PATH_EXTSEP) pos = i; } if (i > pos) { /* An extension already exists in old_path. Go back. */ i = pos; } for ( ; ; ++i, ++new_extname) { if (i >= bufsize) /* overflow */ return NULL; if ((buffer[i] = *new_extname) == '\0') return buffer; } } /* * Makes a backup path name. */ char * opng_path_make_backup(char *buffer, size_t bufsize, const char *path) { static const char bak_extname[] = OPNG_PATH_EXTSEP_STR "bak"; if (strlen(path) + sizeof(bak_extname) > bufsize) return NULL; #if defined OPNG_OS_DOS return opng_path_replace_ext(buffer, bufsize, path, bak_extname); #else /* OPNG_OS_UNIX and others */ strcpy(buffer, path); strcat(buffer, bak_extname); return buffer; #endif } /* * Changes the name of a file system object. */ int opng_os_rename(const char *src_path, const char *dest_path, int clobber) { #if defined OPNG_OS_WINDOWS DWORD dwFlags; #if !defined OPNG_OS_WIN64 if (OPNG_OS_WINDOWS_IS_WIN9X()) { /* MoveFileEx is not available under Win9X; use MoveFile. */ if (MoveFileA(src_path, dest_path)) return 0; if (!clobber) return -1; DeleteFileA(dest_path); return MoveFileA(src_path, dest_path) ? 0 : -1; } #endif dwFlags = clobber ? MOVEFILE_REPLACE_EXISTING : 0; return MoveFileExA(src_path, dest_path, dwFlags) ? 0 : -1; #elif defined OPNG_OS_UNIX if (!clobber) { if (access(dest_path, OPNG_TEST_FILE) >= 0) return -1; } return rename(src_path, dest_path); #else /* generic */ if (opng_test(dest_path, "e") == 0) { if (!clobber) return -1; opng_unlink(dest_path); } return rename(src_path, dest_path); #endif } /* * Copies the attributes (access mode, time stamp, etc.) of a file system * object. */ int opng_os_copy_attr(const char *src_path, const char *dest_path) { #if defined OPNG_OS_WINDOWS HANDLE hFile; FILETIME ftLastWrite; BOOL success; hFile = CreateFileA(src_path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); if (hFile == INVALID_HANDLE_VALUE) return -1; success = GetFileTime(hFile, NULL, NULL, &ftLastWrite); CloseHandle(hFile); if (!success) return -1; hFile = CreateFileA(dest_path, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, (OPNG_OS_WINDOWS_IS_WIN9X() ? 0 : FILE_FLAG_BACKUP_SEMANTICS), 0); if (hFile == INVALID_HANDLE_VALUE) return -1; success = SetFileTime(hFile, NULL, NULL, &ftLastWrite); CloseHandle(hFile); if (!success) return -1; /* TODO: Copy the access mode. */ return 0; #elif defined OPNG_OS_UNIX || defined OPNG_OS_DOSISH struct stat sbuf; int result; if (stat(src_path, &sbuf) != 0) return -1; result = 0; if (chown(dest_path, sbuf.st_uid, sbuf.st_gid) != 0) { /* This is not required to succeed. Fall through. */ } if (chmod(dest_path, sbuf.st_mode) != 0) result = -1; #if defined AT_FDCWD && defined UTIME_NOW && defined UTIME_OMIT { struct timespec times[2]; #if defined OPNG_OS_DARWIN times[0] = sbuf.st_atimespec; times[1] = sbuf.st_mtimespec; #else times[0] = sbuf.st_atim; times[1] = sbuf.st_mtim; #endif if (utimensat(AT_FDCWD, dest_path, times, 0) != 0) result = -1; } #else /* legacy utime */ { struct utimbuf utbuf; utbuf.actime = sbuf.st_atime; utbuf.modtime = sbuf.st_mtime; if (utime(dest_path, &utbuf) != 0) result = -1; } #endif return result; #else /* generic */ (void)src_path; /* unused */ (void)dest_path; /* unused */ /* Always fail. */ return -1; #endif } /* * Creates a new directory. */ int opng_os_create_dir(const char *dirname) { /* Exit early if there is no directory name. */ if (dirname[0] == '\0') return 0; #ifdef OPNG_PATH_DOS if (OPNG_PATH_IS_DRIVE_LETTER(dirname[0]) && dirname[1] == ':' && dirname[2] == '\0') return 0; #endif #if defined OPNG_OS_WINDOWS { size_t dirlen; char *wildname; HANDLE hFind; WIN32_FIND_DATAA wfd; /* Fail early if dirname is too long. */ dirlen = strlen(dirname); if (dirlen * 2 <= dirlen) return -1; /* Find files in (dirname + "\\*") and exit early if dirname exists. */ wildname = (char *)malloc(dirlen + 3); if (wildname == NULL) return -1; strcpy(wildname, dirname); if (strchr(OPNG_PATH_DIRSEP_ALL_STR, wildname[dirlen - 1]) == NULL) wildname[dirlen++] = OPNG_PATH_DIRSEP; wildname[dirlen++] = '*'; wildname[dirlen] = '\0'; hFind = FindFirstFileA(wildname, &wfd); free(wildname); if (hFind != INVALID_HANDLE_VALUE) { FindClose(hFind); return 0; } /* There is no directory, so create one now. */ return CreateDirectoryA(dirname, NULL) ? 0 : -1; } #elif defined OPNG_OS_UNIX || defined OPNG_OS_DOSISH { struct stat sbuf; if (stat(dirname, &sbuf) == 0) return (sbuf.st_mode & S_IFDIR) ? 0 : -1; /* There is no directory, so create one now. */ #if defined OPNG_OS_UNIX return mkdir(dirname, 0777); #else return mkdir(dirname); #endif } #else /* generic */ (void)dirname; /* unused */ /* Always fail. */ return -1; #endif } /* * Determines if the accessibility of the specified file system object * satisfies the specified access mode. */ int opng_os_test(const char *path, const char *mode) { int faccess, freg; faccess = freg = 0; if (strchr(mode, 'f') != NULL) freg = 1; if (strchr(mode, 'r') != NULL) faccess |= OPNG_TEST_READ; if (strchr(mode, 'w') != NULL) faccess |= OPNG_TEST_WRITE; if (strchr(mode, 'x') != NULL) faccess |= OPNG_TEST_EXEC; if (faccess == 0 && !freg) { if (strchr(mode, 'e') == NULL) return 0; } #if defined OPNG_OS_WINDOWS { DWORD attr; attr = GetFileAttributesA(path); if (attr == 0xffffffffU) return -1; if (freg && (attr & FILE_ATTRIBUTE_DIRECTORY)) return -1; if ((faccess & OPNG_TEST_WRITE) && (attr & FILE_ATTRIBUTE_READONLY)) return -1; return 0; } #elif defined OPNG_OS_UNIX || defined OPNG_OS_DOSISH { struct stat sbuf; if (stat(path, &sbuf) != 0) return -1; if (freg && ((sbuf.st_mode & S_IFREG) != S_IFREG)) return -1; if (faccess == 0) return 0; return access(path, faccess); } #else /* generic */ { FILE *stream; if (faccess & OPNG_TEST_WRITE) stream = fopen(path, "r+b"); else stream = fopen(path, "rb"); if (stream == NULL) return -1; fclose(stream); return 0; } #endif } /* * Determines if two accessible paths are equivalent, i.e. they * refer to the same file system object. */ int opng_os_test_eq(const char *path1, const char *path2) { #if defined OPNG_OS_WINDOWS HANDLE hFile1, hFile2; BY_HANDLE_FILE_INFORMATION fileInfo1, fileInfo2; int result; hFile1 = CreateFileA(path1, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); if (hFile1 == INVALID_HANDLE_VALUE) return -1; hFile2 = CreateFileA(path2, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, 0); if (hFile2 == INVALID_HANDLE_VALUE) { CloseHandle(hFile1); return -1; } if (!GetFileInformationByHandle(hFile1, &fileInfo1) || !GetFileInformationByHandle(hFile2, &fileInfo2)) { /* Can't retrieve the file info. */ result = -1; } else if (fileInfo1.nFileIndexLow == fileInfo2.nFileIndexLow && fileInfo1.nFileIndexHigh == fileInfo2.nFileIndexHigh && fileInfo1.dwVolumeSerialNumber == fileInfo2.dwVolumeSerialNumber) { /* The two paths have the same ID on the same volume. */ result = 1; } else { /* The two paths have different IDs or sit on different volumes. */ result = 0; } CloseHandle(hFile1); CloseHandle(hFile2); return result; #elif defined OPNG_OS_UNIX || defined OPNG_OS_DOSISH struct stat sbuf1, sbuf2; if (stat(path1, &sbuf1) != 0 || stat(path2, &sbuf2) != 0) { /* Can't stat the paths. */ return -1; } if (sbuf1.st_dev == sbuf2.st_dev && sbuf1.st_ino == sbuf2.st_ino) { /* The two paths have the same device and inode numbers. */ /* The inode numbers are reliable only if they're not 0. */ return (sbuf1.st_ino != 0) ? 1 : -1; } else { /* The two paths have different device or inode numbers. */ return 0; } #else /* generic */ (void)path1; /* unused */ (void)path2; /* unused */ /* Always unknown. */ return -1; #endif } /* * Removes a directory entry. */ int opng_os_unlink(const char *path) { #if defined OPNG_OS_WINDOWS return DeleteFileA(path) ? 0 : -1; #elif defined OPNG_OS_UNIX || defined OPNG_OS_DOSISH return unlink(path); #else /* generic */ return remove(path); #endif } optipng-0.7.7/src/optipng/ioutil.h000066400000000000000000000171011343170417500171370ustar00rootroot00000000000000/* * ioutil.h * I/O utilities. * * Copyright (C) 2003-2017 Cosmin Truta and the Contributing Authors. * * This software is distributed under the zlib license. * Please see the accompanying LICENSE file. */ #ifndef OPNG_IOUTIL_H_ #define OPNG_IOUTIL_H_ #include /* * File offset and size types: * * opng_foffset_t: the file offset type (a signed integer type) * OPNG_FOFFSET_MIN: the minimum value (less than 0) * OPNG_FOFFSET_MAX: the maximum value (greater than 0) * OPNG_FOFFSET_SCNd: macro for scanf format specifier ("%d"-like) * OPNG_FOFFSET_SCNx: macro for scanf format specifier ("%x"-like) * OPNG_FOFFSET_PRId: macro for printf format specifier ("%d"-like) * OPNG_FOFFSET_PRIx: macro for printf format specifier ("%x"-like) * OPNG_FOFFSET_PRIX: macro for printf format specifier ("%X"-like) * * opng_fsize_t: the file size type (an unsigned integer type) * OPNG_FSIZE_MAX: the maximum value * OPNG_FSIZE_SCNu: macro for scanf format specifier ("%u"-like) * OPNG_FSIZE_SCNx: macro for scanf format specifier ("%x"-like) * OPNG_FSIZE_PRIu: macro for printf format specifier ("%u"-like) * OPNG_FSIZE_PRIx: macro for printf format specifier ("%x"-like) * OPNG_FSIZE_PRIX: macro for printf format specifier ("%X"-like) */ #include #if (LONG_MAX > 0x7fffffffL) || (LONG_MAX > INT_MAX) typedef long opng_foffset_t; #define OPNG_FOFFSET_MIN LONG_MIN #define OPNG_FOFFSET_MAX LONG_MAX #define OPNG_FOFFSET_SCNd "ld" #define OPNG_FOFFSET_SCNx "lx" #define OPNG_FOFFSET_PRId "ld" #define OPNG_FOFFSET_PRIx "lx" #define OPNG_FOFFSET_PRIX "lX" typedef unsigned long opng_fsize_t; #define OPNG_FSIZE_MAX ULONG_MAX #define OPNG_FSIZE_SCNu "lu" #define OPNG_FSIZE_SCNx "lx" #define OPNG_FSIZE_PRIu "lu" #define OPNG_FSIZE_PRIx "lx" #define OPNG_FSIZE_PRIX "lX" #elif defined _I64_MAX && (defined _WIN32 || defined __WIN32__) typedef __int64 opng_foffset_t; #define OPNG_FOFFSET_MIN _I64_MIN #define OPNG_FOFFSET_MAX _I64_MAX #define OPNG_FOFFSET_SCNd "I64d" #define OPNG_FOFFSET_SCNx "I64x" #define OPNG_FOFFSET_PRId "I64d" #define OPNG_FOFFSET_PRIx "I64x" #define OPNG_FOFFSET_PRIX "I64X" typedef unsigned __int64 opng_fsize_t; #define OPNG_FSIZE_MAX _UI64_MAX #define OPNG_FSIZE_SCNu "I64u" #define OPNG_FSIZE_SCNx "I64x" #define OPNG_FSIZE_PRIu "I64u" #define OPNG_FSIZE_PRIx "I64x" #define OPNG_FSIZE_PRIX "I64X" #else #include #include typedef int_least64_t opng_foffset_t; #define OPNG_FOFFSET_MIN INT_LEAST64_MIN #define OPNG_FOFFSET_MAX INT_LEAST64_MAX #define OPNG_FOFFSET_SCNd SCNdLEAST64 #define OPNG_FOFFSET_SCNx SCNxLEAST64 #define OPNG_FOFFSET_PRId PRIdLEAST64 #define OPNG_FOFFSET_PRIx PRIxLEAST64 #define OPNG_FOFFSET_PRIX PRIXLEAST64 typedef uint_least64_t opng_fsize_t; #define OPNG_FSIZE_MAX UINT_LEAST64_MAX #define OPNG_FSIZE_SCNu SCNuLEAST64 #define OPNG_FSIZE_SCNx SCNxLEAST64 #define OPNG_FSIZE_PRIu PRIuLEAST64 #define OPNG_FSIZE_PRIx PRIxLEAST64 #define OPNG_FSIZE_PRIX PRIXLEAST64 #endif #ifdef __cplusplus extern "C" { #endif /* * Returns the current value of the file position indicator. * On error, the function returns (opng_foffset_t)(-1). */ opng_foffset_t opng_ftello(FILE *stream); /* * Sets the file position indicator at the specified file offset. * On success, the function returns 0. On error, it returns -1. */ int opng_fseeko(FILE *stream, opng_foffset_t offset, int whence); /* * Reads a block of data from the specified file offset. * The file-position indicator is saved and restored after reading. * The file buffer is flushed before and after reading. * On success, the function returns the number of bytes read. * On error, it returns 0. */ size_t opng_freado(FILE *stream, opng_foffset_t offset, int whence, void *block, size_t blocksize); /* * Writes a block of data at the specified file offset. * The file-position indicator is saved and restored after writing. * The file buffer is flushed before and after writing. * On success, the function returns the number of bytes written. * On error, it returns 0. */ size_t opng_fwriteo(FILE *stream, opng_foffset_t offset, int whence, const void *block, size_t blocksize); /* * Gets the size of the specified file stream. * This function may change the file position indicator. * On success, the function returns 0. On error, it returns -1. */ int opng_fgetsize(FILE *stream, opng_fsize_t *size); /* * Makes a new path name by replacing the directory component of * a specified path name. * The new directory name can be the empty string, indicating that * the resulting path has no directory. Otherwise, the directory * name should follow the conventions specific to the host operating * system, and may optionally be ended with the directory separator * (e.g. "/" on Unix). * On success, the function returns buffer. * On error, it returns NULL. */ char * opng_path_replace_dir(char *buffer, size_t bufsize, const char *old_path, const char *new_dirname); /* * Makes a new path name by replacing the extension component of * a specified path name. * The new extension name can be the empty string, indicating that * the resulting path has no extension. Otherwise, the extension * name must begin with the extension separator (e.g. "." on Unix). * On success, the function returns buffer. * On error, it returns NULL. */ char * opng_path_replace_ext(char *buffer, size_t bufsize, const char *old_path, const char *new_extname); /* * Makes a backup path name. * On success, the function returns buffer. * On error, it returns NULL. */ char * opng_path_make_backup(char *buffer, size_t bufsize, const char *path); /* * Changes the name of a file system object. * On success, the function returns 0. * On error, it returns -1. */ int opng_os_rename(const char *src_path, const char *dest_path, int clobber); /* * Copies the attributes (access mode, time stamp, etc.) of a file system * object. * On success, the function returns 0. * On error, it returns -1. */ int opng_os_copy_attr(const char *src_path, const char *dest_path); /* * Creates a new directory. * If the directory is successfully created, or if it already exists, * the function returns 0. * Otherwise, it returns -1. */ int opng_os_create_dir(const char *dirname); /* * Determines if the accessibility of the specified file system object * satisfies the specified access mode. The access mode consists of one * or more characters that indicate the checks to be performed, as follows: * 'e': the path exists; it needs not be a regular file. * 'f': the path exists and is a regular file. * 'r': the path exists and read permission is granted. * 'w': the path exists and write permission is granted. * 'x': the path exists and execute permission is granted. * For example, to determine if a file can be opened for reading using * fopen(), use "fr" in the access mode. * If all checks succeed, the function returns 0. * Otherwise, it returns -1. */ int opng_os_test(const char *path, const char *mode); /* * Determines if two accessible paths are equivalent, i.e. they * refer to the same file system object. * If the two paths are equivalent, the function returns 1. * If the two paths are not equivalent, the function returns 0. * If at least one path is not accessible or does not exist, or * if the check cannot be performed, the function returns -1. */ int opng_os_test_eq(const char *path1, const char *path2); /* * Removes a directory entry. * On success, the function returns 0. * On error, it returns -1. */ int opng_os_unlink(const char *path); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* OPNG_IOUTIL_H_ */ optipng-0.7.7/src/optipng/man/000077500000000000000000000000001343170417500162345ustar00rootroot00000000000000optipng-0.7.7/src/optipng/man/Makefile.in000066400000000000000000000016301343170417500203010ustar00rootroot00000000000000.PHONY: all test check dist clean distclean install uninstall .PRECIOUS: Makefile prefix = @prefix@ mandir = @mandir@ man1dir = @man1dir@ all: optipng.man.txt optipng.man.ps optipng.man.pdf optipng.man.html optipng.man.txt: optipng.1 nroff -man -c -Tascii $< | col -b -x | uniq > $@ optipng.man.ps: optipng.1 groff -man -Tps -P-g $< > $@ optipng.man.pdf: optipng.man.ps ps2pdf $< $@ optipng.man.html: optipng.1 groff -man -Thtml -P-l $< > $@ test: check: dist: optipng.man.txt optipng.man.pdf optipng.man.html cp -f -p optipng.man.txt ../../../doc/ cp -f -p optipng.man.pdf ../../../doc/ cp -f -p optipng.man.html ../../../doc/ clean: rm -f optipng.man.txt rm -f optipng.man.ps rm -f optipng.man.pdf rm -f optipng.man.html distclean: clean rm -f Makefile install: optipng.1 mkdir -p $(DESTDIR)$(man1dir) cp -f -p optipng.1 $(DESTDIR)$(man1dir) uninstall: rm -f $(DESTDIR)$(man1dir)/optipng.1 optipng-0.7.7/src/optipng/man/optipng.1000066400000000000000000000265461343170417500200130ustar00rootroot00000000000000.TH OPTIPNG 1 "2017-Dec-27" "OptiPNG version 0.7.7" .SH NAME .B OptiPNG \- Optimize Portable Network Graphics files .SH SYNOPSIS .B optipng [\fB\-?\fP | \fB\-h\fP | \fB\-help\fP] .br .B optipng [\fIoptions...\fP] \fIfiles...\fP .SH DESCRIPTION The .B OptiPNG program shall attempt to \fIoptimize\fP PNG files, i.e. reduce their size to a minimum, without losing semantic information. In addition, this program shall perform a suite of auxiliary functions like integrity checks, metadata recovery and pixmap-to-PNG conversion. .P The optimization attempts are not guaranteed to succeed. Valid PNG files that cannot be optimized by this program are normally left intact; their size will not grow. The user may request to override this default behavior. .SH FILES The input files are raster image files encoded either in PNG format (the native format), or in an external format. The currently supported external formats are GIF, BMP, PNM and TIFF. .P .B OptiPNG processes each image file given in the command line as follows: .P \- If the image is in PNG format: .IP Attempts to optimize the given file in-place. If optimization is successful, or if the option \fB\-force\fP is enabled, replaces the original file with its optimized version. The original file is backed up if the option \fB\-keep\fP is enabled. .P \- If the image is in an external format: .IP Creates an optimized PNG version of the given file. The output file name is composed from the original file name and the \fC.png\fP extension. .P Existing files are \fInot\fP overwritten, unless the option \fB\-clobber\fP is enabled. .SH OPTIONS .SS "General options" .TP \fB\-?\fP, \fB\-h\fP, \fB\-help\fP Show a complete summary of options. .TP \fB\-backup\fP, \fB\-keep\fP Keep a backup of the modified files. .TP \fB\-clobber\fP Overwrite the existing output and backup files. .br Under this option, if the option \fB\-backup\fP is not enabled, the old backups of the overwritten files are deleted. .TP \fB\-dir\fP \fIdirectory\fP Write the output files to \fIdirectory\fP. .TP \fB\-fix\fP Enable error recovery. This option has no effect on valid input files. .br The program will spend a reasonable amount of effort to recover as much data as possible, without increasing the output file size, but the success cannot be generally guaranteed. The program may even increase the file size, e.g., by reconstructing missing critical data. Under this option, integrity shall take precedence over file size. .br When this option is not used, the invalid input files are left unprocessed. .TP \fB\-force\fP Enforce writing of a new output file. .br This option overrides the program's decision not to write such file, e.g. when the PNG input is digitally signed (using dSIG), or when the PNG output becomes larger than the PNG input. .TP \fB\-log\fP \fIfile\fP Log messages to \fIfile\fP. For safety reasons, \fIfile\fP must have the extension \fC.log\fP. .br This option is deprecated and will be removed eventually. Use shell redirection. .TP \fB\-out\fP \fIfile\fP Write output file to \fIfile\fP. The command line must contain exactly one input file. .TP \fB\-preserve\fP Preserve file attributes (time stamps, file access rights, etc.) where applicable. .TP \fB\-quiet\fP, \fB\-silent\fP Run in quiet mode. .br The messages are still written to the log file if the option \fB\-log\fP is enabled. .TP \fB\-simulate\fP Run in simulation mode: perform the trials, but do not create output files. .TP \fB\-v\fP Enable the options \fB\-verbose\fP and \fB\-version\fP. .TP \fB\-verbose\fP Run in verbose mode. .TP \fB\-version\fP Show copyright, version and build info. .TP \fB\-\-\fP Stop option switch parsing. .SS "PNG encoding and optimization options" .TP \fB\-o\fP \fIlevel\fP Select the optimization level. .br The optimization level 0 enables a set of optimization operations that require minimal effort. There will be no changes to image attributes like bit depth or color type, and no recompression of existing IDAT datastreams. .br The optimization level 1 enables a single IDAT compression trial. The trial chosen is what \fBOptiPNG\fP \fIthinks\fP it's probably the most effective. .br The optimization levels 2 and higher enable multiple IDAT compression trials; the higher the level, the more trials. .br The behavior and the default value of this option may change across different program versions. Use the option \fB\-h\fP to see the details pertaining to your specific version. .TP \fB\-f\fP \fIfilters\fP Select the PNG delta filters. .br The \fIfilters\fP argument is specified as a rangeset (e.g. \fB\-f0\-5\fP), and the default \fIfilters\fP value depends on the optimization level set by the option \fB\-o\fP. .br The filter values 0, 1, 2, 3 and 4 indicate static filtering, and correspond to the standard PNG filter codes (\fINone\fP, \fILeft\fP, \fIUp\fP, \fIAverage\fP and \fIPaeth\fP, respectively). The filter value 5 indicates adaptive filtering, whose effect is defined by the \fBlibpng\fP(3) library used by \fBOptiPNG\fP. .TP \fB\-full\fP Produce a full report on IDAT. This option might slow down the trials. .TP \fB\-i\fP \fItype\fP Select the interlace type (0\-1). .br If the interlace type 0 is selected, the output image shall be non-interlaced (i.e. progressive-scanned). If the interlace type 1 is selected, the output image shall be interlaced using the \fIAdam7\fP method. .br By default, the output shall have the same interlace type as the input. .TP \fB\-nb\fP Do not apply bit depth reduction. .TP \fB\-nc\fP Do not apply color type reduction. .TP \fB\-np\fP Do not apply palette reduction. .TP \fB\-nx\fP Do not apply any lossless image reduction: enable the options \fB\-nb\fP, \fB\-nc\fP and \fB\-np\fP. .TP \fB\-nz\fP Do not recode IDAT datastreams. .br The IDAT optimization operations that do not require recoding (e.g. IDAT chunk concatenation) are still performed. .br This option has effect on PNG input files only. .TP \fB\-zc\fP \fIlevels\fP Select the zlib compression levels used in IDAT compression. .br The \fIlevels\fP argument is specified as a rangeset (e.g. \fB\-zc6\-9\fP), and the default \fIlevels\fP value depends on the optimization level set by the option \fB\-o\fP. .br The effect of this option is defined by the \fBzlib\fP(3) library used by \fBOptiPNG\fP. .TP \fB\-zm\fP \fIlevels\fP Select the zlib memory levels used in IDAT compression. .br The \fIlevels\fP argument is specified as a rangeset (e.g. \fB\-zm8\-9\fP), and the default \fIlevels\fP value depends on the optimization level set by the option \fB\-o\fP. .br The effect of this option is defined by the \fBzlib\fP(3) library used by \fBOptiPNG\fP. .TP \fB\-zs\fP \fIstrategies\fP Select the zlib compression strategies used in IDAT compression. .br The \fIstrategies\fP argument is specified as a rangeset (e.g. \fB\-zs0\-3\fP), and the default \fIstrategies\fP value depends on the optimization level set by the option \fB\-o\fP. .br The effect of this option is defined by the \fBzlib\fP(3) library used by \fBOptiPNG\fP. .TP \fB\-zw\fP \fIsize\fP Select the zlib window size (32k,16k,8k,4k,2k,1k,512,256) used in IDAT compression. .br The \fIsize\fP argument can be specified either in bytes (e.g. 16384) or kilobytes (e.g. 16k). The default \fIsize\fP value is set to the lowest window size that yields an IDAT output as big as if yielded by the value 32768. .br The effect of this option is defined by the \fBzlib\fP(3) library used by \fBOptiPNG\fP. .SS "Editing options" .TP \fB\-snip\fP Cut one image out of multi-image, animation or video files. .br Depending on the input format, this may be either the first or the most relevant (e.g. the largest) image. .TP \fB\-strip\fP \fIobjects\fP Strip metadata objects from a PNG file. .br PNG metadata is the information stored in any ancillary chunk except tRNS. (tRNS represents the alpha channel, which, even if ignored in rendering, is still a proper image channel in the RGBA color space.) .br The only option currently supported is \fB\-strip all\fP. .SS "Notes" Options may come in any order (except for \fB\-\-\fP), before, after, or alternating with file names. Option names are case-insensitive and may be abbreviated to their shortest unique prefix. .P Some options may have arguments that follow the option name, separated by whitespace or the equal sign ('\fB=\fP'). If the option argument is a number or a rangeset, the separator may be omitted. For example: .IP \fB\-out\fP \fCnewfile.png\fP \ <=> \ \fB\-out=\fP\fCnewfile.png\fP .br \fB\-o3\fP \ <=> \ \fB\-o 3\fP \ <=> \ \fB\-o=3\fP .br \fB\-f0,3\-5\fP \ <=> \ \fB\-f 0,3\-5\fP \ <=> \ \fB\-f=0,3\-5\fP .P Rangeset arguments are cumulative; e.g. .IP \fB\-f0 \-f3\-5\fP \ <=> \ \fB\-f0,3\-5\fP .br \fB\-zs0 \-zs1 \-zs2\-3\fP \ <=> \ \fB\-zs0,1,2,3\fP \ <=> \ \fB\-zs0\-3\fP .SH "EXTENDED DESCRIPTION" The PNG optimization algorithm consists of the following steps: .TP 4 1. Reduce the bit depth, the color type and the color palette of the image. This step may reduce the size of the uncompressed image, which, indirectly, may reduce the size of the compressed image (i.e. the size of the output PNG file). .TP 4 2. Run a suite of compression methods and strategies and select the compression parameters that yield the smallest output file. .TP 4 3. Store all IDAT contents into a single chunk, eliminating the overhead incurred by repeated IDAT headers and CRCs. .TP 4 4. Set the zlib window size inside IDAT to a mininum that does not affect the compression ratio, reducing the memory requirements of PNG decoders. .P Not all of the above steps need to be executed. The behavior depends on the actual input files and user options. .P Step 1 may be customized via the no-reduce options \fB\-nb\fP, \fB\-nc\fP, \fB\-np\fP and \fB\-nx\fP. Step 2 may be customized via the \fB\-o\fP option, and may be fine-tuned via the options \fB\-zc\fP, \fB\-zm\fP, \fB\-zs\fP and \fB\-zw\fP. Step 3 is always executed. Step 4 is executed only if a new IDAT is being created, and may be fine-tuned via the option \fB\-zw\fP. .P Extremely exhaustive searches are not generally expected to yield significant improvements in compression ratio, and are recommended to advanced users only. .SH EXAMPLES \fCoptipng file.png \ \ \ \ \ \fP# default speed .br \fCoptipng -o5 file.png \ \fP# slow .br \fCoptipng -o7 file.png \ \fP# very slow .SH BUGS Lossless image reductions are not completely implemented. (This does \fInot\fP affect the integrity of the output files.) Here are the missing pieces: .IP \- The color palette reductions are implemented only partially. .br \- The bit depth reductions below 8, for grayscale images, are not implemented yet. .P Encoding of images whose total IDAT size exceeds 2GB is not supported. .P TIFF support is limited to uncompressed, PNG-compatible (grayscale, RGB and RGBA) images. .P Metadata is not imported from the external image formats. .P There is no support for pipes, streams, extended file attributes or access control lists. .SH "SEE ALSO" \fBpng\fP(5), \fBlibpng\fP(3), \fBzlib\fP(3), \fBpngcrush\fP(1), \fBpngrewrite\fP(1). .SH STANDARDS The files produced by \fBOptiPNG\fP are compliant with \fBPNG\-2003\fP: .br Glenn Randers-Pehrson et al. \fIPortable Network Graphics (PNG) Specification, Second Edition\fP. .br W3C Recommendation 10 November 2003; ISO/IEC IS 15948:2003 (E). .br \fChttp://www.w3.org/TR/PNG/\fP .SH AUTHOR \fBOptiPNG\fP is written and maintained by Cosmin Truta. .PP This manual page was originally written by Nelson A. de Oliveira for the Debian Project. It was later updated by Cosmin Truta, and is now part of the \fBOptiPNG\fP distribution. optipng-0.7.7/src/optipng/optim.c000066400000000000000000001705421343170417500167660ustar00rootroot00000000000000/* * optim.c * The main PNG optimization engine. * * Copyright (C) 2001-2017 Cosmin Truta and the Contributing Authors. * * This software is distributed under the zlib license. * Please see the accompanying LICENSE file. */ #include #include #include #include #include #include "optipng.h" #include "proginfo.h" #include "bitset.h" #include "ioutil.h" #include "opngreduc.h" #include "png.h" #include "pngxtern.h" #include "pngxutil.h" #include "ratio.h" #include "zlib.h" /* * User exception setup. */ #include "cexcept.h" define_exception_type(const char *); struct exception_context the_exception_context[1]; /* * The optimization level presets. */ static const struct opng_preset { const char *compr_level; const char *mem_level; const char *strategy; const char *filter; } presets[OPNG_OPTIM_LEVEL_MAX + 1] = { /* { -zc -zm -zs -f } */ { "", "", "", "" }, /* -o0 */ { "", "", "", "" }, /* -o1 */ { "9", "8", "0-", "0,5" }, /* -o2 */ { "9", "8-9", "0-", "0,5" }, /* -o3 */ { "9", "8", "0-", "0-" }, /* -o4 */ { "9", "8-9", "0-", "0-" }, /* -o5 */ { "1-9", "8", "0-", "0-" }, /* -o6 */ { "1-9", "8-9", "0-", "0-" } /* -o7 */ }; /* * The filter table. */ static const int filter_table[OPNG_FILTER_MAX + 1] = { PNG_FILTER_NONE, /* -f0 */ PNG_FILTER_SUB, /* -f1 */ PNG_FILTER_UP, /* -f2 */ PNG_FILTER_AVG, /* -f3 */ PNG_FILTER_PAETH, /* -f4 */ PNG_ALL_FILTERS /* -f5 */ }; /* * Status flags. */ enum { INPUT_IS_PNG_FILE = 0x0001, INPUT_HAS_PNG_DATASTREAM = 0x0002, INPUT_HAS_PNG_SIGNATURE = 0x0004, INPUT_HAS_DIGITAL_SIGNATURE = 0x0008, INPUT_HAS_MULTIPLE_IMAGES = 0x0010, INPUT_HAS_APNG = 0x0020, INPUT_HAS_STRIPPED_DATA = 0x0040, INPUT_HAS_JUNK = 0x0080, INPUT_HAS_ERRORS = 0x0100, OUTPUT_NEEDS_NEW_FILE = 0x1000, OUTPUT_NEEDS_NEW_IDAT = 0x2000, OUTPUT_HAS_ERRORS = 0x4000 }; /* * The chunks handled by OptiPNG. */ static const png_byte sig_PLTE[4] = { 0x50, 0x4c, 0x54, 0x45 }; static const png_byte sig_tRNS[4] = { 0x74, 0x52, 0x4e, 0x53 }; static const png_byte sig_IDAT[4] = { 0x49, 0x44, 0x41, 0x54 }; static const png_byte sig_IEND[4] = { 0x49, 0x45, 0x4e, 0x44 }; static const png_byte sig_bKGD[4] = { 0x62, 0x4b, 0x47, 0x44 }; static const png_byte sig_hIST[4] = { 0x68, 0x49, 0x53, 0x54 }; static const png_byte sig_sBIT[4] = { 0x73, 0x42, 0x49, 0x54 }; static const png_byte sig_dSIG[4] = { 0x64, 0x53, 0x49, 0x47 }; static const png_byte sig_acTL[4] = { 0x61, 0x63, 0x54, 0x4c }; static const png_byte sig_fcTL[4] = { 0x66, 0x63, 0x54, 0x4c }; static const png_byte sig_fdAT[4] = { 0x66, 0x64, 0x41, 0x54 }; /* * The optimization engine. * (Since the engine is not thread-safe, there isn't much to put in here...) */ static struct opng_engine_struct { int started; } engine; /* * The optimization process. */ static struct opng_process_struct { unsigned int status; int num_iterations; opng_foffset_t in_datastream_offset; opng_fsize_t in_file_size, out_file_size; opng_fsize_t in_idat_size, out_idat_size; opng_fsize_t best_idat_size, max_idat_size; png_uint_32 in_plte_trns_size, out_plte_trns_size; png_uint_32 reductions; opng_bitset_t compr_level_set, mem_level_set, strategy_set, filter_set; int best_compr_level, best_mem_level, best_strategy, best_filter; } process; /* * The optimization process limits. */ static const opng_fsize_t idat_size_max = PNG_UINT_31_MAX; static const char *idat_size_max_string = "2GB"; /* * The optimization process summary. */ static struct opng_summary_struct { unsigned int file_count; unsigned int err_count; unsigned int fix_count; unsigned int snip_count; } summary; /* * The optimized image. */ static struct opng_image_struct { png_uint_32 width; /* IHDR */ png_uint_32 height; int bit_depth; int color_type; int compression_type; int filter_type; int interlace_type; png_bytepp row_pointers; /* IDAT */ png_colorp palette; /* PLTE */ int num_palette; png_color_16p background_ptr; /* bKGD */ png_color_16 background; png_uint_16p hist; /* hIST */ png_color_8p sig_bit_ptr; /* sBIT */ png_color_8 sig_bit; png_bytep trans_alpha; /* tRNS */ int num_trans; png_color_16p trans_color_ptr; png_color_16 trans_color; png_unknown_chunkp unknowns; /* everything else */ int num_unknowns; } image; /* * The user options. */ static struct opng_options options; /* * The user interface. */ static void (*usr_printf)(const char *fmt, ...); static void (*usr_print_cntrl)(int cntrl_code); static void (*usr_progress)(unsigned long num, unsigned long denom); static void (*usr_panic)(const char *msg); /* * More global variables, for quick access and bonus style points. */ static png_structp read_ptr; static png_infop read_info_ptr; static png_structp write_ptr; static png_infop write_info_ptr; /* * Internal debugging tool. */ #define OPNG_ENSURE(cond, msg) \ { if (!(cond)) usr_panic(msg); } /* strong check, no #ifdef's */ /* * Size ratio display. */ static void opng_print_fsize_ratio(opng_fsize_t num, opng_fsize_t denom) { #if OPNG_FSIZE_MAX <= ULONG_MAX #define RATIO_TYPE struct opng_ulratio #define RATIO_CONV_FN opng_ulratio_to_factor_string #else #define RATIO_TYPE struct opng_ullratio #define RATIO_CONV_FN opng_ullratio_to_factor_string #endif char buffer[32]; RATIO_TYPE ratio; int result; ratio.num = num; ratio.denom = denom; result = RATIO_CONV_FN(buffer, sizeof(buffer), &ratio); usr_printf("%s%s", buffer, (result > 0) ? "" : "..."); #undef RATIO_TYPE #undef RATIO_CONV_FN } /* * Size change display. */ static void opng_print_fsize_difference(opng_fsize_t init_size, opng_fsize_t final_size, int show_ratio) { opng_fsize_t difference; int sign; if (init_size <= final_size) { sign = 0; difference = final_size - init_size; } else { sign = 1; difference = init_size - final_size; } if (difference == 0) { usr_printf("no change"); return; } if (difference == 1) usr_printf("1 byte"); else usr_printf("%" OPNG_FSIZE_PRIu " bytes", difference); if (show_ratio && init_size > 0) { usr_printf(" = "); opng_print_fsize_ratio(difference, init_size); } usr_printf((sign == 0) ? " increase" : " decrease"); } /* * Image info display. */ static void opng_print_image_info(int show_dim, int show_depth, int show_type, int show_interlaced) { static const int type_channels[8] = {1, 0, 3, 1, 2, 0, 4, 0}; int channels, printed; printed = 0; if (show_dim) { printed = 1; usr_printf("%lux%lu pixels", (unsigned long)image.width, (unsigned long)image.height); } if (show_depth) { if (printed) usr_printf(", "); printed = 1; channels = type_channels[image.color_type & 7]; if (channels != 1) usr_printf("%dx%d bits/pixel", channels, image.bit_depth); else if (image.bit_depth != 1) usr_printf("%d bits/pixel", image.bit_depth); else usr_printf("1 bit/pixel"); } if (show_type) { if (printed) usr_printf(", "); printed = 1; if (image.color_type & PNG_COLOR_MASK_PALETTE) { if (image.num_palette == 1) usr_printf("1 color"); else usr_printf("%d colors", image.num_palette); if (image.num_trans > 0) usr_printf(" (%d transparent)", image.num_trans); usr_printf(" in palette"); } else { usr_printf((image.color_type & PNG_COLOR_MASK_COLOR) ? "RGB" : "grayscale"); if (image.color_type & PNG_COLOR_MASK_ALPHA) usr_printf("+alpha"); else if (image.trans_color_ptr != NULL) usr_printf("+transparency"); } } if (show_interlaced) { if (image.interlace_type != PNG_INTERLACE_NONE) { if (printed) usr_printf(", "); usr_printf("interlaced"); } } } /* * Warning display. */ static void opng_print_warning(const char *msg) { usr_print_cntrl('\v'); /* VT: new paragraph */ usr_printf("Warning: %s\n", msg); } /* * Error display. */ static void opng_print_error(const char *msg) { usr_print_cntrl('\v'); /* VT: new paragraph */ usr_printf("Error: %s\n", msg); } /* * Warning handler. */ static void opng_warning(png_structp png_ptr, png_const_charp msg) { /* Error in input or output file; processing may continue. */ /* Recovery requires (re)compression of IDAT. */ if (png_ptr == read_ptr) process.status |= (INPUT_HAS_ERRORS | OUTPUT_NEEDS_NEW_IDAT); opng_print_warning(msg); } /* * Error handler. */ static void opng_error(png_structp png_ptr, png_const_charp msg) { /* Error in input or output file; processing must stop. */ /* Recovery requires (re)compression of IDAT. */ if (png_ptr == read_ptr) process.status |= (INPUT_HAS_ERRORS | OUTPUT_NEEDS_NEW_IDAT); Throw msg; } /* * Memory deallocator. */ static void opng_free(void *ptr) { /* This deallocator must be compatible with libpng's memory allocation * routines, png_malloc() and png_free(). * If those routines change, this one must be changed accordingly. */ free(ptr); } /* * IDAT size checker. */ static void opng_check_idat_size(opng_fsize_t size) { if (size > idat_size_max) Throw "IDAT sizes larger than the maximum chunk size " "are currently unsupported"; } /* * Chunk handler. */ static void opng_set_keep_unknown_chunk(png_structp png_ptr, int keep, png_bytep chunk_type) { png_byte chunk_name[5]; /* Call png_set_keep_unknown_chunks() once per each chunk type only. */ memcpy(chunk_name, chunk_type, 4); chunk_name[4] = 0; if (!png_handle_as_unknown(png_ptr, chunk_name)) png_set_keep_unknown_chunks(png_ptr, keep, chunk_name, 1); } /* * Chunk categorization. */ static int opng_is_image_chunk(png_bytep chunk_type) { if ((chunk_type[0] & 0x20) == 0) return 1; /* Although tRNS is listed as ancillary in the PNG specification, it stores * alpha samples, which is critical information. For example, tRNS cannot * be generally ignored when rendering animations. * Operations claimed to be lossless must treat tRNS as a critical chunk. */ if (memcmp(chunk_type, sig_tRNS, 4) == 0) return 1; return 0; } /* * Chunk categorization. */ static int opng_is_apng_chunk(png_bytep chunk_type) { if (memcmp(chunk_type, sig_acTL, 4) == 0 || memcmp(chunk_type, sig_fcTL, 4) == 0 || memcmp(chunk_type, sig_fdAT, 4) == 0) return 1; return 0; } /* * Chunk filter. */ static int opng_allow_chunk(png_bytep chunk_type) { /* Always allow critical chunks and tRNS. */ if (opng_is_image_chunk(chunk_type)) return 1; /* Block all the other chunks if requested. */ if (options.strip_all) return 0; /* Always block the digital signature chunks. */ if (memcmp(chunk_type, sig_dSIG, 4) == 0) return 0; /* Block the APNG chunks when snipping. */ if (options.snip && opng_is_apng_chunk(chunk_type)) return 0; /* Allow all the other chunks. */ return 1; } /* * Chunk handler. */ static void opng_handle_chunk(png_structp png_ptr, png_bytep chunk_type) { int keep; if (opng_is_image_chunk(chunk_type)) return; if (options.strip_all) { process.status |= INPUT_HAS_STRIPPED_DATA | INPUT_HAS_JUNK; opng_set_keep_unknown_chunk(png_ptr, PNG_HANDLE_CHUNK_NEVER, chunk_type); return; } /* Let libpng handle bKGD, hIST and sBIT. */ if (memcmp(chunk_type, sig_bKGD, 4) == 0 || memcmp(chunk_type, sig_hIST, 4) == 0 || memcmp(chunk_type, sig_sBIT, 4) == 0) return; /* Everything else is handled as unknown by libpng. */ keep = PNG_HANDLE_CHUNK_ALWAYS; if (memcmp(chunk_type, sig_dSIG, 4) == 0) { /* Recognize dSIG, but let libpng handle it as unknown. */ process.status |= INPUT_HAS_DIGITAL_SIGNATURE; } else if (opng_is_apng_chunk(chunk_type)) { /* Recognize APNG, but let libpng handle it as unknown. */ process.status |= INPUT_HAS_APNG; if (memcmp(chunk_type, sig_fdAT, 4) == 0) process.status |= INPUT_HAS_MULTIPLE_IMAGES; if (options.snip) { process.status |= INPUT_HAS_JUNK; keep = PNG_HANDLE_CHUNK_NEVER; } } opng_set_keep_unknown_chunk(png_ptr, keep, chunk_type); } /* * Initialization for input handler. */ static void opng_init_read_data(void) { /* The relevant process data members are set to zero, * and nothing else needs to be done at this moment. */ } /* * Initialization for output handler. */ static void opng_init_write_data(void) { process.out_file_size = 0; process.out_plte_trns_size = 0; process.out_idat_size = 0; } /* * Input handler. */ static void opng_read_data(png_structp png_ptr, png_bytep data, size_t length) { FILE *stream = (FILE *)png_get_io_ptr(png_ptr); int io_state = pngx_get_io_state(png_ptr); int io_state_loc = io_state & PNGX_IO_MASK_LOC; png_bytep chunk_sig; /* Read the data. */ if (fread(data, 1, length, stream) != length) png_error(png_ptr, "Can't read the input file or unexpected end of file"); if (process.in_file_size == 0) /* first piece of PNG data */ { OPNG_ENSURE(length == 8, "PNG I/O must start with the first 8 bytes"); process.in_datastream_offset = opng_ftello(stream) - 8; process.status |= INPUT_HAS_PNG_DATASTREAM; if (io_state_loc == PNGX_IO_SIGNATURE) process.status |= INPUT_HAS_PNG_SIGNATURE; if (process.in_datastream_offset == 0) process.status |= INPUT_IS_PNG_FILE; else if (process.in_datastream_offset < 0) png_error(png_ptr, "Can't get the file-position indicator in input file"); process.in_file_size = (opng_fsize_t)process.in_datastream_offset; } process.in_file_size += length; /* Handle the OptiPNG-specific events. */ OPNG_ENSURE((io_state & PNGX_IO_READING) && (io_state_loc != 0), "Incorrect info in png_ptr->io_state"); if (io_state_loc == PNGX_IO_CHUNK_HDR) { /* In libpng 1.4.x and later, the chunk length and the chunk name * are serialized in a single operation. This is also ensured by * the opngio add-on for libpng 1.2.x and earlier. */ OPNG_ENSURE(length == 8, "Reading chunk header, expecting 8 bytes"); chunk_sig = data + 4; if (memcmp(chunk_sig, sig_IDAT, 4) == 0) { OPNG_ENSURE(png_ptr == read_ptr, "Incorrect I/O handler setup"); if (png_get_rows(read_ptr, read_info_ptr) == NULL) /* 1st IDAT */ { OPNG_ENSURE(process.in_idat_size == 0, "Found IDAT with no rows"); /* Allocate the rows here, bypassing libpng. * This allows to initialize the contents and perform recovery * in case of a premature EOF. */ if (png_get_image_height(read_ptr, read_info_ptr) == 0) return; /* premature IDAT; an error will occur later */ OPNG_ENSURE(pngx_malloc_rows(read_ptr, read_info_ptr, 0) != NULL, "Failed allocation of image rows; " "unsafe libpng allocator"); png_data_freer(read_ptr, read_info_ptr, PNG_USER_WILL_FREE_DATA, PNG_FREE_ROWS); } else { /* There is split IDAT overhead. Join IDATs. */ process.status |= INPUT_HAS_JUNK; } process.in_idat_size += png_get_uint_32(data); } else if (memcmp(chunk_sig, sig_PLTE, 4) == 0 || memcmp(chunk_sig, sig_tRNS, 4) == 0) { /* Add the chunk overhead (header + CRC) to the data size. */ process.in_plte_trns_size += png_get_uint_32(data) + 12; } else opng_handle_chunk(png_ptr, chunk_sig); } else if (io_state_loc == PNGX_IO_CHUNK_CRC) { OPNG_ENSURE(length == 4, "Reading chunk CRC, expecting 4 bytes"); } } /* * Output handler. */ static void opng_write_data(png_structp png_ptr, png_bytep data, size_t length) { static int allow_crt_chunk; static int crt_chunk_is_idat; static opng_foffset_t crt_idat_offset; static opng_fsize_t crt_idat_size; static png_uint_32 crt_idat_crc; FILE *stream = (FILE *)png_get_io_ptr(png_ptr); int io_state = pngx_get_io_state(png_ptr); int io_state_loc = io_state & PNGX_IO_MASK_LOC; png_bytep chunk_sig; png_byte buf[4]; OPNG_ENSURE((io_state & PNGX_IO_WRITING) && (io_state_loc != 0), "Incorrect info in png_ptr->io_state"); /* Handle the OptiPNG-specific events. */ if (io_state_loc == PNGX_IO_CHUNK_HDR) { OPNG_ENSURE(length == 8, "Writing chunk header, expecting 8 bytes"); chunk_sig = data + 4; allow_crt_chunk = opng_allow_chunk(chunk_sig); if (memcmp(chunk_sig, sig_IDAT, 4) == 0) { crt_chunk_is_idat = 1; process.out_idat_size += png_get_uint_32(data); /* Abandon the trial if IDAT is bigger than the maximum allowed. */ if (stream == NULL) { if (process.out_idat_size > process.max_idat_size) Throw NULL; /* early interruption, not an error */ } } else /* not IDAT */ { crt_chunk_is_idat = 0; if (memcmp(chunk_sig, sig_PLTE, 4) == 0 || memcmp(chunk_sig, sig_tRNS, 4) == 0) { /* Add the chunk overhead (header + CRC) to the data size. */ process.out_plte_trns_size += png_get_uint_32(data) + 12; } } } else if (io_state_loc == PNGX_IO_CHUNK_CRC) { OPNG_ENSURE(length == 4, "Writing chunk CRC, expecting 4 bytes"); } /* Exit early if this is only a trial. */ if (stream == NULL) return; /* Continue only if the current chunk type is allowed. */ if (io_state_loc != PNGX_IO_SIGNATURE && !allow_crt_chunk) return; /* Here comes an elaborate way of writing the data, in which all IDATs * are joined into a single chunk. * Normally, the user-supplied I/O routines are not so complicated. */ switch (io_state_loc) { case PNGX_IO_CHUNK_HDR: if (crt_chunk_is_idat) { if (crt_idat_offset == 0) { /* This is the header of the first IDAT. */ crt_idat_offset = opng_ftello(stream); /* Try guessing the size of the final (joined) IDAT. */ if (process.best_idat_size > 0) { /* The guess is expected to be right. */ crt_idat_size = process.best_idat_size; } else { /* The guess could be wrong. * The size of the final IDAT will be revised. */ crt_idat_size = length; } png_save_uint_32(data, (png_uint_32)crt_idat_size); /* Start computing the CRC of the final IDAT. */ crt_idat_crc = crc32(0, sig_IDAT, 4); } else { /* This is not the first IDAT. Do not write its header. */ return; } } else { if (crt_idat_offset != 0) { /* This is the header of the first chunk after IDAT. * Finalize IDAT before resuming the normal operation. */ png_save_uint_32(buf, crt_idat_crc); if (fwrite(buf, 1, 4, stream) != 4) io_state = 0; /* error */ process.out_file_size += 4; if (process.out_idat_size != crt_idat_size) { /* The IDAT size has not been guessed correctly. * It must be updated in a non-streamable way. */ OPNG_ENSURE(process.best_idat_size == 0, "Wrong guess of the output IDAT size"); opng_check_idat_size(process.out_idat_size); png_save_uint_32(buf, (png_uint_32)process.out_idat_size); if (opng_fwriteo(stream, crt_idat_offset, SEEK_SET, buf, 4) != 4) io_state = 0; /* error */ } if (io_state == 0) png_error(png_ptr, "Can't finalize IDAT"); crt_idat_offset = 0; } } break; case PNGX_IO_CHUNK_DATA: if (crt_chunk_is_idat) crt_idat_crc = crc32(crt_idat_crc, data, length); break; case PNGX_IO_CHUNK_CRC: if (crt_chunk_is_idat) { /* Defer writing until the first non-IDAT occurs. */ return; } break; } /* Write the data. */ if (fwrite(data, 1, length, stream) != length) png_error(png_ptr, "Can't write the output file"); process.out_file_size += length; } /* * Image info initialization. */ static void opng_clear_image_info(void) { memset(&image, 0, sizeof(image)); } /* * Image info transfer. */ static void opng_load_image_info(png_structp png_ptr, png_infop info_ptr, int load_meta) { memset(&image, 0, sizeof(image)); png_get_IHDR(png_ptr, info_ptr, &image.width, &image.height, &image.bit_depth, &image.color_type, &image.interlace_type, &image.compression_type, &image.filter_type); image.row_pointers = png_get_rows(png_ptr, info_ptr); png_get_PLTE(png_ptr, info_ptr, &image.palette, &image.num_palette); /* Transparency is not considered metadata, although tRNS is ancillary. * See the comment in opng_is_image_chunk() above. */ if (png_get_tRNS(png_ptr, info_ptr, &image.trans_alpha, &image.num_trans, &image.trans_color_ptr)) { /* Double copying (pointer + value) is necessary here * due to an inconsistency in the libpng design. */ if (image.trans_color_ptr != NULL) { image.trans_color = *image.trans_color_ptr; image.trans_color_ptr = &image.trans_color; } } if (!load_meta) return; if (png_get_bKGD(png_ptr, info_ptr, &image.background_ptr)) { /* Same problem as in tRNS. */ image.background = *image.background_ptr; image.background_ptr = &image.background; } png_get_hIST(png_ptr, info_ptr, &image.hist); if (png_get_sBIT(png_ptr, info_ptr, &image.sig_bit_ptr)) { /* Same problem as in tRNS. */ image.sig_bit = *image.sig_bit_ptr; image.sig_bit_ptr = &image.sig_bit; } image.num_unknowns = png_get_unknown_chunks(png_ptr, info_ptr, &image.unknowns); } /* * Image info transfer. */ static void opng_store_image_info(png_structp png_ptr, png_infop info_ptr, int store_meta) { int i; OPNG_ENSURE(image.row_pointers != NULL, "No info in image"); png_set_IHDR(png_ptr, info_ptr, image.width, image.height, image.bit_depth, image.color_type, image.interlace_type, image.compression_type, image.filter_type); png_set_rows(write_ptr, write_info_ptr, image.row_pointers); if (image.palette != NULL) png_set_PLTE(png_ptr, info_ptr, image.palette, image.num_palette); /* Transparency is not considered metadata, although tRNS is ancillary. * See the comment in opng_is_image_chunk() above. */ if (image.trans_alpha != NULL || image.trans_color_ptr != NULL) png_set_tRNS(png_ptr, info_ptr, image.trans_alpha, image.num_trans, image.trans_color_ptr); if (!store_meta) return; if (image.background_ptr != NULL) png_set_bKGD(png_ptr, info_ptr, image.background_ptr); if (image.hist != NULL) png_set_hIST(png_ptr, info_ptr, image.hist); if (image.sig_bit_ptr != NULL) png_set_sBIT(png_ptr, info_ptr, image.sig_bit_ptr); if (image.num_unknowns != 0) { png_set_unknown_chunks(png_ptr, info_ptr, image.unknowns, image.num_unknowns); /* This should be handled by libpng. */ for (i = 0; i < image.num_unknowns; ++i) png_set_unknown_chunk_location(png_ptr, info_ptr, i, image.unknowns[i].location); } } /* * Image info destruction. */ static void opng_destroy_image_info(void) { png_uint_32 i; int j; if (image.row_pointers == NULL) return; /* nothing to clean up */ for (i = 0; i < image.height; ++i) opng_free(image.row_pointers[i]); opng_free(image.row_pointers); opng_free(image.palette); opng_free(image.trans_alpha); opng_free(image.hist); for (j = 0; j < image.num_unknowns; ++j) opng_free(image.unknowns[j].data); opng_free(image.unknowns); /* DO NOT deallocate background_ptr, sig_bit_ptr, trans_color_ptr. * See the comments regarding double copying inside opng_load_image_info(). */ /* Clear the space here and do not worry about double-deallocation issues * that might arise later on. */ memset(&image, 0, sizeof(image)); } /* * Image file reading. */ static void opng_read_file(FILE *infile) { const char *fmt_name; int num_img; png_uint_32 reductions; const char * volatile err_msg; /* volatile is required by cexcept */ Try { read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, opng_error, opng_warning); read_info_ptr = png_create_info_struct(read_ptr); if (read_info_ptr == NULL) Throw "Out of memory"; /* Override the default libpng settings. */ png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0); png_set_user_limits(read_ptr, PNG_UINT_31_MAX, PNG_UINT_31_MAX); /* Read the input image file. */ opng_init_read_data(); pngx_set_read_fn(read_ptr, infile, opng_read_data); fmt_name = NULL; num_img = pngx_read_image(read_ptr, read_info_ptr, &fmt_name, NULL); if (num_img <= 0) Throw "Unrecognized image file format"; if (num_img > 1) process.status |= INPUT_HAS_MULTIPLE_IMAGES; if ((process.status & INPUT_IS_PNG_FILE) && (process.status & INPUT_HAS_MULTIPLE_IMAGES)) { /* pngxtern can't distinguish between APNG and proper PNG. */ fmt_name = (process.status & INPUT_HAS_PNG_SIGNATURE) ? "APNG" : "APNG datastream"; } OPNG_ENSURE(fmt_name != NULL, "No format name from pngxtern"); if (process.in_file_size == 0) { if (opng_fgetsize(infile, &process.in_file_size) < 0) { opng_print_warning("Can't get the correct file size"); process.in_file_size = 0; } } err_msg = NULL; /* everything is ok */ } Catch (err_msg) { /* If the critical info has been loaded, treat all errors as warnings. * This enables a more advanced data recovery. */ if (opng_validate_image(read_ptr, read_info_ptr)) { png_warning(read_ptr, err_msg); err_msg = NULL; } } Try { if (err_msg != NULL) Throw err_msg; /* Display format and image information. */ if (strcmp(fmt_name, "PNG") != 0) { usr_printf("Importing %s", fmt_name); if (process.status & INPUT_HAS_MULTIPLE_IMAGES) { if (!(process.status & INPUT_IS_PNG_FILE)) usr_printf(" (multi-image or animation)"); if (options.snip) usr_printf("; snipping..."); } usr_printf("\n"); } opng_load_image_info(read_ptr, read_info_ptr, 1); opng_print_image_info(1, 1, 1, 1); usr_printf("\n"); /* Choose the applicable image reductions. */ reductions = OPNG_REDUCE_ALL & ~OPNG_REDUCE_METADATA; if (options.nb) reductions &= ~OPNG_REDUCE_BIT_DEPTH; if (options.nc) reductions &= ~OPNG_REDUCE_COLOR_TYPE; if (options.np) reductions &= ~OPNG_REDUCE_PALETTE; if (options.nz && (process.status & INPUT_HAS_PNG_DATASTREAM)) { /* Do not reduce files with PNG datastreams under -nz. */ reductions = OPNG_REDUCE_NONE; } if (process.status & INPUT_HAS_DIGITAL_SIGNATURE) { /* Do not reduce signed files. */ reductions = OPNG_REDUCE_NONE; } if ((process.status & INPUT_IS_PNG_FILE) && (process.status & INPUT_HAS_MULTIPLE_IMAGES) && (reductions != OPNG_REDUCE_NONE) && !options.snip) { usr_printf( "Can't reliably reduce APNG file; disabling reductions.\n" "(Did you want to -snip and optimize the first frame?)\n"); reductions = OPNG_REDUCE_NONE; } /* Try to reduce the image. */ process.reductions = opng_reduce_image(read_ptr, read_info_ptr, reductions); /* If the image is reduced, enforce full compression. */ if (process.reductions != OPNG_REDUCE_NONE) { opng_load_image_info(read_ptr, read_info_ptr, 1); usr_printf("Reducing image to "); opng_print_image_info(0, 1, 1, 0); usr_printf("\n"); } /* Change the interlace type if required. */ if (options.interlace >= 0 && image.interlace_type != options.interlace) { image.interlace_type = options.interlace; /* A change in interlacing requires IDAT recoding. */ process.status |= OUTPUT_NEEDS_NEW_IDAT; } } Catch (err_msg) { /* Do the cleanup, then rethrow the exception. */ png_data_freer(read_ptr, read_info_ptr, PNG_DESTROY_WILL_FREE_DATA, PNG_FREE_ALL); png_destroy_read_struct(&read_ptr, &read_info_ptr, NULL); Throw err_msg; } /* Destroy the libpng structures, but leave the enclosed data intact * to allow further processing. */ png_data_freer(read_ptr, read_info_ptr, PNG_USER_WILL_FREE_DATA, PNG_FREE_ALL); png_destroy_read_struct(&read_ptr, &read_info_ptr, NULL); } /* * PNG file writing. * * If the output file is NULL, PNG encoding is still done, * but no file is written. */ static void opng_write_file(FILE *outfile, int compression_level, int memory_level, int compression_strategy, int filter) { const char * volatile err_msg; /* volatile is required by cexcept */ OPNG_ENSURE(compression_level >= OPNG_COMPR_LEVEL_MIN && compression_level <= OPNG_COMPR_LEVEL_MAX && memory_level >= OPNG_MEM_LEVEL_MIN && memory_level <= OPNG_MEM_LEVEL_MAX && compression_strategy >= OPNG_STRATEGY_MIN && compression_strategy <= OPNG_STRATEGY_MAX && filter >= OPNG_FILTER_MIN && filter <= OPNG_FILTER_MAX, "Invalid encoding parameters"); Try { write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, opng_error, opng_warning); write_info_ptr = png_create_info_struct(write_ptr); if (write_info_ptr == NULL) Throw "Out of memory"; png_set_compression_level(write_ptr, compression_level); png_set_compression_mem_level(write_ptr, memory_level); png_set_compression_strategy(write_ptr, compression_strategy); png_set_filter(write_ptr, PNG_FILTER_TYPE_BASE, filter_table[filter]); if (compression_strategy != Z_HUFFMAN_ONLY && compression_strategy != Z_RLE) { if (options.window_bits > 0) png_set_compression_window_bits(write_ptr, options.window_bits); } else { #ifdef WBITS_8_OK png_set_compression_window_bits(write_ptr, 8); #else png_set_compression_window_bits(write_ptr, 9); #endif } /* Override the default libpng settings. */ png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS, NULL, 0); png_set_user_limits(write_ptr, PNG_UINT_31_MAX, PNG_UINT_31_MAX); /* Write the PNG stream. */ opng_store_image_info(write_ptr, write_info_ptr, (outfile != NULL)); opng_init_write_data(); pngx_set_write_fn(write_ptr, outfile, opng_write_data, NULL); png_write_png(write_ptr, write_info_ptr, 0, NULL); err_msg = NULL; /* everything is ok */ } Catch (err_msg) { /* Set IDAT size to invalid. */ process.out_idat_size = idat_size_max + 1; } /* Destroy the libpng structures. */ png_destroy_write_struct(&write_ptr, &write_info_ptr); if (err_msg != NULL) Throw err_msg; } /* * PNG file copying. */ static void opng_copy_file(FILE *infile, FILE *outfile) { volatile png_bytep buf; /* volatile is required by cexcept */ const png_uint_32 buf_size_incr = 0x1000; png_uint_32 buf_size, length; png_byte chunk_hdr[8]; const char * volatile err_msg; write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, opng_error, opng_warning); if (write_ptr == NULL) Throw "Out of memory"; opng_init_write_data(); pngx_set_write_fn(write_ptr, outfile, opng_write_data, NULL); Try { buf = NULL; buf_size = 0; /* Write the signature in the output file. */ pngx_write_sig(write_ptr); /* Copy all chunks until IEND. */ /* Error checking is done only at a very basic level. */ do { if (fread(chunk_hdr, 8, 1, infile) != 1) /* length + name */ Throw "Read error"; length = png_get_uint_32(chunk_hdr); if (length > PNG_UINT_31_MAX) { if (buf == NULL && length == 0x89504e47UL) /* "\x89PNG" */ { /* Skip the signature. */ continue; } Throw "Data error"; } if (length + 4 > buf_size) { png_free(write_ptr, buf); buf_size = (((length + 4) + (buf_size_incr - 1)) / buf_size_incr) * buf_size_incr; buf = (png_bytep)png_malloc(write_ptr, buf_size); /* Do not use realloc() here, it's slower. */ } if (fread(buf, length + 4, 1, infile) != 1) /* data + crc */ Throw "Read error"; png_write_chunk(write_ptr, chunk_hdr + 4, buf, length); } while (memcmp(chunk_hdr + 4, sig_IEND, 4) != 0); err_msg = NULL; /* everything is ok */ } Catch (err_msg) { } png_free(write_ptr, buf); png_destroy_write_struct(&write_ptr, NULL); if (err_msg != NULL) Throw err_msg; } /* * Iteration initialization. */ static void opng_init_iteration(opng_bitset_t cmdline_set, opng_bitset_t mask_set, const char *preset, opng_bitset_t *output_set) { opng_bitset_t preset_set; int check; *output_set = cmdline_set & mask_set; if (*output_set == 0 && cmdline_set != 0) Throw "Iteration parameter(s) out of range"; if (*output_set == 0 || options.optim_level >= 0) { check = opng_strparse_rangeset_to_bitset(&preset_set, preset, mask_set); OPNG_ENSURE(check == 0, "[internal] Invalid preset"); *output_set |= preset_set & mask_set; } } /* * Iteration initialization. */ static void opng_init_iterations(void) { opng_bitset_t compr_level_set, mem_level_set, strategy_set, filter_set; opng_bitset_t strategy_singles_set; int preset_index; int t1, t2; /* Set the IDAT size limit. The trials that pass this limit will be * abandoned, as there will be no need to wait until their completion. * This limit may further decrease as iterations go on. */ if ((process.status & OUTPUT_NEEDS_NEW_IDAT) || options.full) process.max_idat_size = idat_size_max; else { OPNG_ENSURE(process.in_idat_size > 0, "No IDAT in input"); /* Add the input PLTE and tRNS sizes to the initial max IDAT size, * to account for the changes that may occur during reduction. * This incurs a negligible overhead on processing only: the final * IDAT size will not be affected, because a precise check will be * performed at the end, inside opng_finish_iterations(). */ process.max_idat_size = process.in_idat_size + process.in_plte_trns_size; } /* Get preset_index from options.optim_level, but leave the latter intact, * because the effect of "optipng -o2 -z... -f..." is slightly different * from the effect of "optipng -z... -f..." (without "-o"). */ preset_index = options.optim_level; if (preset_index < 0) preset_index = OPNG_OPTIM_LEVEL_DEFAULT; else if (preset_index > OPNG_OPTIM_LEVEL_MAX) preset_index = OPNG_OPTIM_LEVEL_MAX; /* Initialize the iteration sets. * Combine the user-defined values with the optimization presets. */ opng_init_iteration(options.compr_level_set, OPNG_COMPR_LEVEL_SET_MASK, presets[preset_index].compr_level, &compr_level_set); opng_init_iteration(options.mem_level_set, OPNG_MEM_LEVEL_SET_MASK, presets[preset_index].mem_level, &mem_level_set); opng_init_iteration(options.strategy_set, OPNG_STRATEGY_SET_MASK, presets[preset_index].strategy, &strategy_set); opng_init_iteration(options.filter_set, OPNG_FILTER_SET_MASK, presets[preset_index].filter, &filter_set); /* Replace the empty sets with the libpng's "best guess" heuristics. */ if (compr_level_set == 0) opng_bitset_set(&compr_level_set, Z_BEST_COMPRESSION); /* -zc9 */ if (mem_level_set == 0) opng_bitset_set(&mem_level_set, 8); if (image.bit_depth < 8 || image.palette != NULL) { if (strategy_set == 0) opng_bitset_set(&strategy_set, Z_DEFAULT_STRATEGY); /* -zs0 */ if (filter_set == 0) opng_bitset_set(&filter_set, 0); /* -f0 */ } else { if (strategy_set == 0) opng_bitset_set(&strategy_set, Z_FILTERED); /* -zs1 */ if (filter_set == 0) opng_bitset_set(&filter_set, 5); /* -f0 */ } /* Store the results into process. */ process.compr_level_set = compr_level_set; process.mem_level_set = mem_level_set; process.strategy_set = strategy_set; process.filter_set = filter_set; strategy_singles_set = (1 << Z_HUFFMAN_ONLY) | (1 << Z_RLE); t1 = opng_bitset_count(compr_level_set) * opng_bitset_count(strategy_set & ~strategy_singles_set); t2 = opng_bitset_count(strategy_set & strategy_singles_set); process.num_iterations = (t1 + t2) * opng_bitset_count(mem_level_set) * opng_bitset_count(filter_set); OPNG_ENSURE(process.num_iterations > 0, "Invalid iteration parameters"); } /* * Iteration. */ static void opng_iterate(void) { opng_bitset_t compr_level_set, mem_level_set, strategy_set, filter_set; int compr_level, mem_level, strategy, filter; int counter; int line_reused; OPNG_ENSURE(process.num_iterations > 0, "Iterations not initialized"); compr_level_set = process.compr_level_set; mem_level_set = process.mem_level_set; strategy_set = process.strategy_set; filter_set = process.filter_set; if ((process.num_iterations == 1) && (process.status & OUTPUT_NEEDS_NEW_IDAT)) { /* There is only one combination. Select it and return. */ process.best_idat_size = 0; /* unknown */ process.best_compr_level = opng_bitset_find_first(compr_level_set); process.best_mem_level = opng_bitset_find_first(mem_level_set); process.best_strategy = opng_bitset_find_first(strategy_set); process.best_filter = opng_bitset_find_first(filter_set); return; } /* Prepare for the big iteration. */ process.best_idat_size = idat_size_max + 1; process.best_compr_level = -1; process.best_mem_level = -1; process.best_strategy = -1; process.best_filter = -1; /* Iterate through the "hyper-rectangle" (zc, zm, zs, f). */ usr_printf("\nTrying:\n"); line_reused = 0; counter = 0; for (filter = OPNG_FILTER_MIN; filter <= OPNG_FILTER_MAX; ++filter) { if (!opng_bitset_test(filter_set, filter)) continue; for (strategy = OPNG_STRATEGY_MIN; strategy <= OPNG_STRATEGY_MAX; ++strategy) { if (!opng_bitset_test(strategy_set, strategy)) continue; if (strategy == Z_HUFFMAN_ONLY) { /* Under Z_HUFFMAN_ONLY, all compression levels * (deflate_fast and deflate_slow combined) * produce the same output. Pick level 1. */ compr_level_set = 0; opng_bitset_set(&compr_level_set, 1); } else if (strategy == Z_RLE) { /* Under Z_RLE, all deflate_fast compression levels produce * the same output. Ditto about the deflate_slow levels. * Pick level 9, in preference for deflate_slow. */ compr_level_set = 0; opng_bitset_set(&compr_level_set, 9); } else { /* Restore compr_level_set. */ compr_level_set = process.compr_level_set; } for (compr_level = OPNG_COMPR_LEVEL_MAX; compr_level >= OPNG_COMPR_LEVEL_MIN; --compr_level) { if (!opng_bitset_test(compr_level_set, compr_level)) continue; for (mem_level = OPNG_MEM_LEVEL_MAX; mem_level >= OPNG_MEM_LEVEL_MIN; --mem_level) { if (!opng_bitset_test(mem_level_set, mem_level)) continue; usr_printf(" zc = %d zm = %d zs = %d f = %d", compr_level, mem_level, strategy, filter); usr_progress(counter, process.num_iterations); ++counter; opng_write_file(NULL, compr_level, mem_level, strategy, filter); if (process.out_idat_size > idat_size_max) { if (options.verbose) { usr_printf("\t\tIDAT too big\n"); line_reused = 0; } else { usr_print_cntrl('\r'); /* CR: reset line */ line_reused = 1; } continue; } usr_printf("\t\tIDAT size = %" OPNG_FSIZE_PRIu "\n", process.out_idat_size); line_reused = 0; if (process.best_idat_size < process.out_idat_size) { /* The current best size is smaller than the last size. * Discard the last iteration. */ continue; } if (process.best_idat_size == process.out_idat_size && (process.best_strategy == Z_HUFFMAN_ONLY || process.best_strategy == Z_RLE)) { /* The current best size is equal to the last size; * the current best strategy is already the fastest. * Discard the last iteration. */ continue; } process.best_compr_level = compr_level; process.best_mem_level = mem_level; process.best_strategy = strategy; process.best_filter = filter; process.best_idat_size = process.out_idat_size; if (!options.full) process.max_idat_size = process.out_idat_size; } } } } if (line_reused) usr_print_cntrl(-31); /* minus N: erase N chars from start of line */ OPNG_ENSURE(counter == process.num_iterations, "Inconsistent iteration counter"); usr_progress(counter, process.num_iterations); } /* * Iteration finalization. */ static void opng_finish_iterations(void) { if (process.best_idat_size + process.out_plte_trns_size < process.in_idat_size + process.in_plte_trns_size) process.status |= OUTPUT_NEEDS_NEW_IDAT; if (process.status & OUTPUT_NEEDS_NEW_IDAT) { if (process.best_idat_size <= idat_size_max) { usr_printf("\nSelecting parameters:\n"); usr_printf(" zc = %d zm = %d zs = %d f = %d", process.best_compr_level, process.best_mem_level, process.best_strategy, process.best_filter); if (process.best_idat_size > 0) { /* At least one trial has been run. */ usr_printf("\t\tIDAT size = %" OPNG_FSIZE_PRIu, process.best_idat_size); } usr_printf("\n"); } else { /* The compressed image data is larger than the maximum allowed. */ usr_printf(" zc = * zm = * zs = * f = *\t\tIDAT size > %s\n", idat_size_max_string); } } } /* * Image file optimization. */ static void opng_optimize_impl(const char *infile_name) { static FILE *infile, *outfile; /* static or volatile is required */ static const char *infile_name_local; /* by cexcept */ static const char *outfile_name, *bakfile_name; static int new_outfile, has_backup; char name_buf[FILENAME_MAX], tmp_buf[FILENAME_MAX]; const char * volatile err_msg; memset(&process, 0, sizeof(process)); if (options.force) process.status |= OUTPUT_NEEDS_NEW_IDAT; err_msg = NULL; /* prepare for error handling */ infile_name_local = infile_name; if ((infile = fopen(infile_name_local, "rb")) == NULL) Throw "Can't open the input file"; Try { opng_read_file(infile); } Catch (err_msg) { OPNG_ENSURE(err_msg != NULL, "Mysterious error in opng_read_file"); } fclose(infile); /* finally */ if (err_msg != NULL) Throw err_msg; /* rethrow */ /* Check the error flag. This must be the first check. */ if (process.status & INPUT_HAS_ERRORS) { usr_printf("Recoverable errors found in input."); if (options.fix) { usr_printf(" Fixing...\n"); process.status |= OUTPUT_NEEDS_NEW_FILE; } else { usr_printf(" Rerun " PROGRAM_NAME " with -fix enabled.\n"); Throw "Previous error(s) not fixed"; } } /* Check the junk flag. */ if (process.status & INPUT_HAS_JUNK) process.status |= OUTPUT_NEEDS_NEW_FILE; /* Check the PNG signature and datastream flags. */ if (!(process.status & INPUT_HAS_PNG_SIGNATURE)) process.status |= OUTPUT_NEEDS_NEW_FILE; if (process.status & INPUT_HAS_PNG_DATASTREAM) { if (options.nz && (process.status & OUTPUT_NEEDS_NEW_IDAT)) { usr_printf( "IDAT recoding is necessary, but is disabled by the user.\n"); Throw "Can't continue"; } } else process.status |= OUTPUT_NEEDS_NEW_IDAT; /* Check the digital signature flag. */ if (process.status & INPUT_HAS_DIGITAL_SIGNATURE) { usr_printf("Digital signature found in input."); if (options.force) { usr_printf(" Erasing...\n"); process.status |= OUTPUT_NEEDS_NEW_FILE; } else { usr_printf(" Rerun " PROGRAM_NAME " with -force enabled.\n"); Throw "Can't optimize digitally-signed files"; } } /* Check the multi-image flag. */ if (process.status & INPUT_HAS_MULTIPLE_IMAGES) { if (!options.snip && !(process.status & INPUT_IS_PNG_FILE)) { usr_printf("Conversion to PNG requires snipping. " "Rerun " PROGRAM_NAME " with -snip enabled.\n"); Throw "Incompatible input format"; } } if ((process.status & INPUT_HAS_APNG) && options.snip) process.status |= OUTPUT_NEEDS_NEW_FILE; /* Check the stripped-data flag. */ if (process.status & INPUT_HAS_STRIPPED_DATA) usr_printf("Stripping metadata...\n"); /* Initialize the output file name. */ outfile_name = NULL; if (!(process.status & INPUT_IS_PNG_FILE)) { if (opng_path_replace_ext(name_buf, sizeof(name_buf), infile_name_local, ".png") == NULL) Throw "Can't create the output file (name too long)"; outfile_name = name_buf; } if (options.out_name != NULL) outfile_name = options.out_name; /* override the old name */ if (options.dir_name != NULL) { const char *tmp_name; if (outfile_name != NULL) { strcpy(tmp_buf, outfile_name); tmp_name = tmp_buf; } else tmp_name = infile_name_local; if (opng_path_replace_dir(name_buf, sizeof(name_buf), tmp_name, options.dir_name) == NULL) Throw "Can't create the output file (name too long)"; outfile_name = name_buf; } if (outfile_name == NULL) { outfile_name = infile_name_local; new_outfile = 0; } else { int test_eq = opng_os_test_eq(infile_name_local, outfile_name); if (test_eq >= 0) new_outfile = (test_eq == 0); else { /* We don't know if the two paths point to the same file. * Use a crude path name comparison. */ new_outfile = (strcmp(infile_name_local, outfile_name) != 0); } } /* Initialize the backup file name. */ bakfile_name = tmp_buf; if (new_outfile) { if (opng_path_make_backup(tmp_buf, sizeof(tmp_buf), outfile_name) == NULL) bakfile_name = NULL; } else { if (opng_path_make_backup(tmp_buf, sizeof(tmp_buf), infile_name_local) == NULL) bakfile_name = NULL; } /* Check the name even in simulation mode, to ensure a uniform behavior. */ if (bakfile_name == NULL) Throw "Can't create backup file (name too long)"; /* Check the backup file before engaging in lengthy trials. */ if (!options.simulate && opng_os_test(outfile_name, "e") == 0) { if (new_outfile && !options.backup && !options.clobber) { usr_printf("The output file exists. " "Rerun " PROGRAM_NAME " with -backup enabled.\n"); Throw "Can't overwrite the output file"; } if (opng_os_test(outfile_name, "fw") != 0 || (!options.clobber && opng_os_test(bakfile_name, "e") == 0)) Throw "Can't back up the existing output file"; } /* Display the input IDAT/file sizes. */ if (process.status & INPUT_HAS_PNG_DATASTREAM) usr_printf("Input IDAT size = %" OPNG_FSIZE_PRIu " bytes\n", process.in_idat_size); usr_printf("Input file size = %" OPNG_FSIZE_PRIu " bytes\n", process.in_file_size); /* Find the best parameters and see if it's worth recompressing. */ if (!options.nz || (process.status & OUTPUT_NEEDS_NEW_IDAT)) { opng_init_iterations(); opng_iterate(); opng_finish_iterations(); } if (process.status & OUTPUT_NEEDS_NEW_IDAT) { process.status |= OUTPUT_NEEDS_NEW_FILE; opng_check_idat_size(process.best_idat_size); } /* Stop here? */ if (!(process.status & OUTPUT_NEEDS_NEW_FILE)) { usr_printf("\n%s is already optimized.\n", infile_name_local); if (!new_outfile) return; } if (options.simulate) { usr_printf("\nNo output: simulation mode.\n"); return; } /* Make room for the output file. */ if (new_outfile) { usr_printf("\nOutput file: %s\n", outfile_name); if (options.dir_name != NULL) opng_os_create_dir(options.dir_name); has_backup = 0; if (opng_os_test(outfile_name, "e") == 0) { if (opng_os_rename(outfile_name, bakfile_name, options.clobber) != 0) Throw "Can't back up the output file"; has_backup = 1; } } else { if (opng_os_rename(infile_name_local, bakfile_name, options.clobber) != 0) Throw "Can't back up the input file"; has_backup = 1; } outfile = fopen(outfile_name, "wb"); Try { if (outfile == NULL) Throw "Can't open the output file"; if (process.status & OUTPUT_NEEDS_NEW_IDAT) { /* Write a brand new PNG datastream to the output. */ opng_write_file(outfile, process.best_compr_level, process.best_mem_level, process.best_strategy, process.best_filter); } else { /* Copy the input PNG datastream to the output. */ infile = fopen(new_outfile ? infile_name_local : bakfile_name, "rb"); if (infile == NULL) Throw "Can't reopen the input file"; Try { if (process.in_datastream_offset > 0 && opng_fseeko(infile, process.in_datastream_offset, SEEK_SET) != 0) Throw "Can't reposition the input file"; process.best_idat_size = process.in_idat_size; opng_copy_file(infile, outfile); } Catch (err_msg) { OPNG_ENSURE(err_msg != NULL, "Mysterious error in opng_copy_file"); } fclose(infile); /* finally */ if (err_msg != NULL) Throw err_msg; /* rethrow */ } } Catch (err_msg) { if (outfile != NULL) fclose(outfile); /* Restore the original input file and rethrow the exception. */ if (has_backup) { if (opng_os_rename(bakfile_name, new_outfile ? outfile_name : infile_name_local, 1) != 0) opng_print_warning( "Can't recover the original file from backup"); } else { OPNG_ENSURE(new_outfile, "Overwrote input with no temporary backup"); if (opng_os_unlink(outfile_name) != 0) opng_print_warning("Can't remove the broken output file"); } Throw err_msg; /* rethrow */ } /* assert(err_msg == NULL); */ fclose(outfile); /* Preserve file attributes (e.g. ownership, access rights, time stamps) * on request, if possible. */ if (options.preserve) opng_os_copy_attr(new_outfile ? infile_name_local : bakfile_name, outfile_name); /* Remove the backup file if it is not needed. */ if (!new_outfile && !options.backup) { if (opng_os_unlink(bakfile_name) != 0) opng_print_warning("Can't remove the backup file"); } /* Display the output IDAT/file sizes. */ usr_printf("\nOutput IDAT size = %" OPNG_FSIZE_PRIu " bytes", process.out_idat_size); if (process.status & INPUT_HAS_PNG_DATASTREAM) { usr_printf(" ("); opng_print_fsize_difference(process.in_idat_size, process.out_idat_size, 0); usr_printf(")"); } usr_printf("\nOutput file size = %" OPNG_FSIZE_PRIu " bytes (", process.out_file_size); opng_print_fsize_difference(process.in_file_size, process.out_file_size, 1); usr_printf(")\n"); } /* * Engine initialization. */ int opng_initialize(const struct opng_options *init_options, const struct opng_ui *init_ui) { /* Initialize and check the validity of the user interface. */ usr_printf = init_ui->printf_fn; usr_print_cntrl = init_ui->print_cntrl_fn; usr_progress = init_ui->progress_fn; usr_panic = init_ui->panic_fn; if (usr_printf == NULL || usr_print_cntrl == NULL || usr_progress == NULL || usr_panic == NULL) return -1; /* Initialize and adjust the user options. */ options = *init_options; if (options.optim_level == 0) { options.nb = options.nc = options.np = 1; options.nz = 1; } /* Start the engine. */ memset(&summary, 0, sizeof(summary)); engine.started = 1; return 0; } /* * Engine execution. */ int opng_optimize(const char *infile_name) { const char *err_msg; volatile int result; /* volatile not needed, but keeps compilers happy */ OPNG_ENSURE(engine.started, "The OptiPNG engine is not running"); usr_printf("** Processing: %s\n", infile_name); ++summary.file_count; opng_clear_image_info(); Try { opng_optimize_impl(infile_name); if (process.status & INPUT_HAS_ERRORS) { ++summary.err_count; ++summary.fix_count; } if (process.status & INPUT_HAS_MULTIPLE_IMAGES) { if (options.snip) ++summary.snip_count; } result = 0; } Catch (err_msg) { ++summary.err_count; opng_print_error(err_msg); result = -1; } opng_destroy_image_info(); usr_printf("\n"); return result; } /* * Engine finalization. */ int opng_finalize(void) { /* Print the status report. */ if (options.verbose || summary.snip_count > 0 || summary.err_count > 0) { usr_printf("** Status report\n"); usr_printf("%u file(s) have been processed.\n", summary.file_count); if (summary.snip_count > 0) { usr_printf("%u multi-image file(s) have been snipped.\n", summary.snip_count); } if (summary.err_count > 0) { usr_printf("%u error(s) have been encountered.\n", summary.err_count); if (summary.fix_count > 0) usr_printf("%u erroneous file(s) have been fixed.\n", summary.fix_count); } } /* Stop the engine. */ engine.started = 0; return 0; } optipng-0.7.7/src/optipng/optipng.c000066400000000000000000000656521343170417500173230ustar00rootroot00000000000000/* * OptiPNG: Advanced PNG optimization program. * http://optipng.sourceforge.net/ * * Copyright (C) 2001-2017 Cosmin Truta and the Contributing Authors. * * This software is distributed under the zlib license. * Please see the accompanying LICENSE file. * * PNG optimization is described in detail in the PNG-Tech article * "A guide to PNG optimization" * http://optipng.sourceforge.net/pngtech/png_optimization.html * * The idea of running multiple compression trials with different * PNG filters and zlib parameters is inspired from the pngcrush * program by Glenn Randers-Pehrson. * The idea of performing lossless image reductions is inspired * from the pngrewrite program by Jason Summers. */ #include #include #include #include #include #include #include "optipng.h" #include "proginfo.h" #include "bitset.h" #include "png.h" #include "pngxutil.h" #include "zlib.h" static const char *msg_intro = PROGRAM_NAME " version " PROGRAM_VERSION "\n" PROGRAM_COPYRIGHT ".\n"; static const char *msg_license = "This program is open-source software. See LICENSE for more details.\n" "\n" "Portions of this software are based in part on the work of:\n" " Jean-loup Gailly and Mark Adler (zlib)\n" " Glenn Randers-Pehrson and the PNG Development Group (libpng)\n" " Miyasaka Masaru (BMP support)\n" " David Koblas (GIF support)\n"; static const char *msg_help_synopsis = "Synopsis:\n" " optipng [options] files ...\n" "Files:\n" " Image files of type: PNG, BMP, GIF, PNM or TIFF\n"; static const char *msg_help_basic_options = "Basic options:\n" " -?, -h, -help\tshow the extended help\n" " -o \t\toptimization level (0-7)\t\t[default: 2]\n" " -v\t\t\trun in verbose mode / show copyright and version info\n"; static const char *msg_help_options = "Basic options:\n" " -?, -h, -help\tshow this help\n" " -o \t\toptimization level (0-7)\t\t[default: 2]\n" " -v\t\t\trun in verbose mode / show copyright and version info\n" "General options:\n" " -backup, -keep\tkeep a backup of the modified files\n" " -clobber\t\toverwrite existing files\n" #if 0 /* internal */ " -debug\t\tenable debug features\n" #endif " -fix\t\tenable error recovery\n" " -force\t\tenforce writing of a new output file\n" " -preserve\t\tpreserve file attributes if possible\n" " -quiet, -silent\trun in quiet mode\n" " -simulate\t\trun in simulation mode\n" " -out \t\twrite output file to \n" " -dir \twrite output file(s) to \n" " -log \t\tlog messages to \n" " --\t\t\tstop option switch parsing\n" "Optimization options:\n" " -f \tPNG delta filters (0-5)\t\t\t[default: 0,5]\n" " -i \t\tPNG interlace type (0-1)\n" " -zc \tzlib compression levels (1-9)\t\t[default: 9]\n" " -zm \tzlib memory levels (1-9)\t\t[default: 8]\n" " -zs \tzlib compression strategies (0-3)\t[default: 0-3]\n" " -zw \t\tzlib window size (256,512,1k,2k,4k,8k,16k,32k)\n" " -full\t\tproduce a full report on IDAT (might reduce speed)\n" " -nb\t\t\tno bit depth reduction\n" " -nc\t\t\tno color type reduction\n" " -np\t\t\tno palette reduction\n" " -nx\t\t\tno reductions\n" " -nz\t\t\tno IDAT recoding\n" "Editing options:\n" " -snip\t\tcut one image out of multi-image or animation files\n" " -strip \tstrip metadata objects (e.g. \"all\")\n" "Optimization levels:\n" " -o0\t\t<=>\t-o1 -nx -nz\t\t\t\t(0 or 1 trials)\n" " -o1\t\t<=>\t-zc9 -zm8 -zs0 -f0\t\t\t(1 trial)\n" " \t\t(or...)\t-zc9 -zm8 -zs1 -f5\t\t\t(1 trial)\n" " -o2\t\t<=>\t-zc9 -zm8 -zs0-3 -f0,5\t\t\t(8 trials)\n" " -o3\t\t<=>\t-zc9 -zm8-9 -zs0-3 -f0,5\t\t(16 trials)\n" " -o4\t\t<=>\t-zc9 -zm8 -zs0-3 -f0-5\t\t\t(24 trials)\n" " -o5\t\t<=>\t-zc9 -zm8-9 -zs0-3 -f0-5\t\t(48 trials)\n" " -o6\t\t<=>\t-zc1-9 -zm8 -zs0-3 -f0-5\t\t(120 trials)\n" " -o7\t\t<=>\t-zc1-9 -zm8-9 -zs0-3 -f0-5\t\t(240 trials)\n" " -o7 -zm1-9\t<=>\t-zc1-9 -zm1-9 -zs0-3 -f0-5\t\t(1080 trials)\n" "Notes:\n" " The combination for -o1 is chosen heuristically.\n" " Exhaustive combinations such as \"-o7 -zm1-9\" are not generally recommended.\n"; static const char *msg_help_examples = "Examples:\n" " optipng file.png\t\t\t\t\t\t(default speed)\n" " optipng -o5 file.png\t\t\t\t\t(slow)\n" " optipng -o7 file.png\t\t\t\t\t(very slow)\n"; static const char *msg_help_more = "Type \"optipng -h\" for extended help.\n"; static enum { OP_RUN, OP_SHOW_HELP, OP_SHOW_VERSION } operation; static struct { int help; int version; } local_options; static struct opng_options options; static FILE *con_file; static FILE *log_file; static int start_of_line; /* * Error handling. */ static void error(const char *fmt, ...) { va_list arg_ptr; /* Print the error message to stderr and exit. */ fprintf(stderr, "** Error: "); va_start(arg_ptr, fmt); vfprintf(stderr, fmt, arg_ptr); va_end(arg_ptr); fprintf(stderr, "\n"); exit(EXIT_FAILURE); } /* * Panic handling. */ static void panic(const char *msg) { /* Print the panic message to stderr and terminate abnormally. */ fprintf(stderr, "\n** INTERNAL ERROR: %s\n", msg); fprintf(stderr, "Please submit a defect report.\n" PROGRAM_URI "\n\n"); fflush(stderr); if (options.debug) { /* Terminate abnormally, possibly with a stack trace or a core dump. */ abort(); } else { /* Terminate abnormally, cleanly. */ fprintf(stderr, "The execution of this program has been terminated abnormally.\n"); exit(70); /* EX_SOFTWARE */ } } /* * String utility. */ static int opng_strcasecmp(const char *str1, const char *str2) { int ch1, ch2; /* Perform a case-insensitive string comparison. */ for ( ; ; ) { ch1 = tolower(*str1++); ch2 = tolower(*str2++); if (ch1 != ch2) return ch1 - ch2; if (ch1 == 0) return 0; } /* FIXME: This function is not MBCS-aware. */ } /* * String utility. */ static char * opng_strltrim(const char *str) { /* Skip the leading whitespace characters. */ while (isspace(*str)) ++str; return (char *)str; } /* * String utility. */ static char * opng_strtail(const char *str, size_t num) { size_t len; /* Return up to num rightmost characters. */ len = strlen(str); if (len <= num) return (char *)str; return (char *)str + len - num; } /* * String utility. */ static char * opng_strpbrk_digit(const char *str) { for ( ; ; ) { if (*str == 0) return NULL; if (isdigit(*str)) return (char *)str; ++str; } } /* * String conversion utility. */ static int opng_str2ulong(unsigned long *out_val, const char *in_str, int allow_multiplier) { const char *begin_ptr; char *end_ptr; unsigned long multiplier; /* Extract the value from the string. */ /* Do not allow the minus sign, not even for -0. */ begin_ptr = end_ptr = opng_strltrim(in_str); if (*begin_ptr >= '0' && *begin_ptr <= '9') *out_val = strtoul(begin_ptr, &end_ptr, 10); if (begin_ptr == end_ptr) { errno = EINVAL; /* matching failure */ *out_val = 0; return -1; } if (allow_multiplier) { /* Check for the following SI suffixes: * 'K' or 'k': kibi (1024) * 'M': mebi (1024 * 1024) * 'G': gibi (1024 * 1024 * 1024) */ if (*end_ptr == 'k' || *end_ptr == 'K') { ++end_ptr; multiplier = 1024UL; } else if (*end_ptr == 'M') { ++end_ptr; multiplier = 1024UL * 1024UL; } else if (*end_ptr == 'G') { ++end_ptr; multiplier = 1024UL * 1024UL * 1024UL; } else multiplier = 1; if (multiplier > 1) { if (*out_val > ULONG_MAX / multiplier) { errno = ERANGE; /* overflow */ *out_val = ULONG_MAX; } else *out_val *= multiplier; } } /* Check for trailing garbage. */ if (*opng_strltrim(end_ptr) != 0) { errno = EINVAL; /* garbage in input */ return -1; } return 0; } /* * Command line utility. */ static void err_option_arg(const char *opt, const char *opt_arg) { /* Issue an error regarding the incorrect value of the option argument. */ if (opt_arg == NULL || *opng_strltrim(opt_arg) == 0) error("Missing argument for option %s", opt); else error("Invalid argument for option %s: %s", opt, opt_arg); } /* * Command line utility. */ static int check_num_option(const char *opt, const char *opt_arg, int lowest, int highest) { unsigned long value; /* Extract the numeric value from the option argument. */ if (opng_str2ulong(&value, opt_arg, 0) != 0 || value > INT_MAX || (int)value < lowest || (int)value > highest) err_option_arg(opt, opt_arg); return (int)value; } /* * Command line utility. */ static int check_power2_option(const char *opt, const char *opt_arg, int lowest, int highest) { unsigned long value; int result; /* Extract the exact log2 of the numeric value from the option argument. */ /* Allow the 'k', 'M', 'G' suffixes. */ if (opng_str2ulong(&value, opt_arg, 1) == 0) { if (lowest < 0) lowest = 0; if (highest > (int)(CHAR_BIT * sizeof(long) - 2)) highest = (int)(CHAR_BIT * sizeof(long) - 2); for (result = lowest; result <= highest; ++result) { if ((1UL << result) == value) return result; } } err_option_arg(opt, opt_arg); return -1; } /* * Command line utility. */ static opng_bitset_t check_rangeset_option(const char *opt, const char *opt_arg, opng_bitset_t result_mask) { opng_bitset_t result; /* Extract the rangeset from the option argument. * Accept only non-empty rangesets that fit in the given range. */ if (opng_strparse_rangeset_to_bitset(&result, opt_arg, result_mask) != 0) result = OPNG_BITSET_EMPTY; if ((result & result_mask) != result) result = OPNG_BITSET_EMPTY; if (result == OPNG_BITSET_EMPTY) err_option_arg(opt, opt_arg); return result; } /* * Command line utility. */ static void check_obj_option(const char *opt, const char *opt_arg) { unsigned int i; if (strcmp("all", opt_arg) == 0) return; /* Issue an error about the unrecognized option argument. */ /* Make it specific on whether this argument is a chunk name. */ for (i = 0; i < 4; ++i) { /* Do not use isalpha(), because it is locale-dependent. */ if (!((opt_arg[i] >= 'A' && opt_arg[i] <= 'Z') || (opt_arg[i] >= 'a' && opt_arg[i] <= 'z'))) break; } if (i == 4 && opt_arg[i] == 0) error("Manipulation of individual chunks is not implemented"); else err_option_arg(opt, opt_arg); } /* * Command line parsing. */ static int scan_option(const char *str, char opt_buf[], size_t opt_buf_size, const char **opt_arg_ptr) { const char *ptr; unsigned int opt_len; /* Check if arg is an "-option". */ if (str[0] != '-' || str[1] == 0) /* no "-option", or just "-" */ return 0; /* Extract the normalized option, and possibly the option argument. */ opt_len = 0; ptr = str + 1; while (*ptr == '-') /* "--option", "---option", etc. */ ++ptr; if (*ptr == 0) /* "--" */ --ptr; for ( ; ; ) { if (opt_len < opt_buf_size) /* truncate "-verylongoption" */ opt_buf[opt_len] = (char)tolower(*ptr); ++opt_len; ++ptr; if (*ptr == 0 || isspace(*ptr)) /* "-option" or "-option arg" */ { while (isspace(*ptr)) ++ptr; *opt_arg_ptr = (*ptr != 0) ? ptr : NULL; break; } if (*ptr == '=') /* "-option=arg" */ { ++ptr; *opt_arg_ptr = ptr; break; } } /* Finalize the normalized option. */ if (opt_buf_size > 0) { if (opt_len < opt_buf_size) opt_buf[opt_len] = '\0'; else opt_buf[opt_buf_size - 1] = '\0'; } return 1; } /* * Command line parsing. */ static void parse_args(int argc, char *argv[]) { char *arg; char opt[16]; size_t opt_len; const char *xopt; int simple_opt, stop_switch; opng_bitset_t set; int val; unsigned int file_count; int i; /* Initialize. */ memset(&options, 0, sizeof(options)); options.optim_level = -1; options.interlace = -1; file_count = 0; /* Iterate over args. */ stop_switch = 0; for (i = 1; i < argc; ++i) { arg = argv[i]; if (stop_switch || scan_option(arg, opt, sizeof(opt), &xopt) < 1) { ++file_count; continue; /* leave file names for process_files() */ } opt_len = strlen(opt); /* Prevent process_files() from seeing this arg. */ argv[i] = NULL; /* Normalize the options that allow juxtaposed arguments. */ if ((strchr("fio", opt[0]) != NULL && isdigit(opt[1])) || (opt[0] == 'z' && isalpha(opt[1]) && isdigit(opt[2]))) { /* -f0-5 <=> -f=0-5; -i1 <=> -i=1; -o3 <=> -o=3; * -zc3-9 <=> -zc=3-9; etc. */ opt_len = (size_t)(opng_strpbrk_digit(opt) - opt); opt[opt_len] = '\0'; xopt = opng_strpbrk_digit(arg); } /* Check the simple options (without option arguments). */ simple_opt = 1; if (strcmp("-", opt) == 0) { /* -- */ stop_switch = 1; } else if (strcmp("?", opt) == 0 || strncmp("help", opt, opt_len) == 0) { /* -? | -h | ... | -help */ local_options.help = 1; } else if ((strncmp("backup", opt, opt_len) == 0) || (strncmp("keep", opt, opt_len) == 0)) { /* -b | ... | -backup | -k | ... | -keep */ options.backup = 1; } else if (strncmp("clobber", opt, opt_len) == 0) { /* -c | ... | -clobber */ options.clobber = 1; } else if (strcmp("debug", opt) == 0) { /* -debug */ /* Do not abbreviate this internal option. */ options.debug = 1; } else if (strncmp("fix", opt, opt_len) == 0 && opt_len >= 2) { /* -fi | -fix */ options.fix = 1; } else if (strncmp("force", opt, opt_len) == 0 && opt_len >= 2) { /* -fo | ... | -force */ options.force = 1; } else if (strncmp("full", opt, opt_len) == 0 && opt_len >= 2) { /* -fu | ... | -full */ options.full = 1; } else if (strcmp("nb", opt) == 0) { /* -nb */ options.nb = 1; } else if (strcmp("nc", opt) == 0) { /* -nc */ options.nc = 1; } else if (strcmp("np", opt) == 0) { /* -np */ options.np = 1; } else if (strcmp("nx", opt) == 0) { /* -nx */ options.nb = options.nc = options.np = 1; /* options.nm = 1; */ } else if (strcmp("nz", opt) == 0) { /* -nz */ options.nz = 1; } else if (strncmp("preserve", opt, opt_len) == 0) { /* -p | ... | -preserve */ options.preserve = 1; } else if ((strncmp("quiet", opt, opt_len) == 0) || (strncmp("silent", opt, opt_len) == 0 && opt_len >= 3)) { /* -q | ... | -quiet | -sil | ... | -silent */ options.quiet = 1; } else if (strncmp("simulate", opt, opt_len) == 0 && opt_len >= 3) { /* -sim | ... | -simulate */ options.simulate = 1; } else if (strncmp("snip", opt, opt_len) == 0 && opt_len >= 2) { /* -sn | ... | -snip */ options.snip = 1; } else if (strcmp("v", opt) == 0) { /* -v */ options.verbose = 1; local_options.version = 1; } else if (strncmp("verbose", opt, opt_len) == 0 && opt_len >= 4) { /* -verb | ... | -verbose */ options.verbose = 1; } else if (strncmp("version", opt, opt_len) == 0 && opt_len >= 4) { /* -vers | ... | -version */ local_options.version = 1; } else /* possibly an option with an argument */ { simple_opt = 0; if (xopt == NULL) { if (++i < argc) { xopt = argv[i]; /* Prevent process_files() from seeing this xopt. */ argv[i] = NULL; } else { /* Last option in command line; assume an empty xopt. */ xopt = ""; } } } /* Check the options that have option arguments. */ if (simple_opt) { if (xopt != NULL) error("No argument allowed for option: %s", arg); } else if (strcmp("o", opt) == 0) { /* -o NUM */ val = check_num_option("-o", xopt, 0, INT_MAX); if (options.optim_level < 0) options.optim_level = val; else if (options.optim_level != val) error("Multiple optimization levels are not permitted"); } else if (strcmp("i", opt) == 0) { /* -i NUM */ val = check_num_option("-i", xopt, 0, 1); if (options.interlace < 0) options.interlace = val; else if (options.interlace != val) error("Multiple interlace types are not permitted"); } else if (strcmp("f", opt) == 0) { /* -f SET */ set = check_rangeset_option("-f", xopt, OPNG_FILTER_SET_MASK); options.filter_set |= set; } else if (strcmp("zc", opt) == 0) { /* -zc SET */ set = check_rangeset_option("-zc", xopt, OPNG_COMPR_LEVEL_SET_MASK); options.compr_level_set |= set; } else if (strcmp("zm", opt) == 0) { /* -zm SET */ set = check_rangeset_option("-zm", xopt, OPNG_MEM_LEVEL_SET_MASK); options.mem_level_set |= set; } else if (strcmp("zs", opt) == 0) { /* -zs SET */ set = check_rangeset_option("-zs", xopt, OPNG_STRATEGY_SET_MASK); options.strategy_set |= set; } else if (strcmp("zw", opt) == 0) { /* -zw NUM */ val = check_power2_option("-zw", xopt, 8, 15); if (options.window_bits == 0) options.window_bits = val; else if (options.window_bits != val) error("Multiple window sizes are not permitted"); } else if (strncmp("strip", opt, opt_len) == 0 && opt_len >= 2) { /* -st OBJ | ... | -strip OBJ */ check_obj_option("-strip", xopt); options.strip_all = 1; } else if (strncmp("out", opt, opt_len) == 0 && opt_len >= 2) { /* -ou PATH | -out PATH */ if (options.out_name != NULL) error("Multiple output file names are not permitted"); if (xopt[0] == 0) err_option_arg("-out", NULL); options.out_name = xopt; } else if (strncmp("dir", opt, opt_len) == 0) { /* -d PATH | ... | -dir PATH */ if (options.dir_name != NULL) error("Multiple output dir names are not permitted"); if (xopt[0] == 0) err_option_arg("-dir", NULL); options.dir_name = xopt; } else if (strncmp("log", opt, opt_len) == 0) { /* -l PATH | ... | -log PATH */ if (options.log_name != NULL) error("Multiple log file names are not permitted"); if (xopt[0] == 0) err_option_arg("-log", NULL); options.log_name = xopt; } else { error("Unrecognized option: %s", arg); } } /* Finalize. */ if (options.out_name != NULL) { if (file_count > 1) error("The option -out requires one input file"); if (options.dir_name != NULL) error("The options -out and -dir are mutually exclusive"); } if (options.log_name != NULL) { if (opng_strcasecmp(".log", opng_strtail(options.log_name, 4)) != 0) error("To prevent accidental data corruption, " "the log file name must end with \".log\""); } if (local_options.help) operation = OP_SHOW_HELP; else if (file_count != 0) operation = OP_RUN; else if (local_options.version) operation = OP_SHOW_VERSION; else operation = OP_SHOW_HELP; } /* * Application-defined printf callback. */ static void app_printf(const char *fmt, ...) { va_list arg_ptr; if (fmt[0] == 0) return; start_of_line = (fmt[strlen(fmt) - 1] == '\n') ? 1 : 0; if (con_file != NULL) { va_start(arg_ptr, fmt); vfprintf(con_file, fmt, arg_ptr); va_end(arg_ptr); } if (log_file != NULL) { va_start(arg_ptr, fmt); vfprintf(log_file, fmt, arg_ptr); va_end(arg_ptr); } } /* * Application-defined control print callback. */ static void app_print_cntrl(int cntrl_code) { const char *con_str, *log_str; int i; if (cntrl_code == '\r') { /* CR: reset line in console, new line in log file. */ con_str = "\r"; log_str = "\n"; start_of_line = 1; } else if (cntrl_code == '\v') { /* VT: new line if current line is not empty, nothing otherwise. */ if (!start_of_line) { con_str = log_str = "\n"; start_of_line = 1; } else con_str = log_str = ""; } else if (cntrl_code < 0 && cntrl_code > -80 && start_of_line) { /* Minus N: erase first N characters from line, in console only. */ if (con_file != NULL) { for (i = 0; i > cntrl_code; --i) fputc(' ', con_file); } con_str = "\r"; log_str = ""; } else { /* Unhandled control code (due to internal error): show err marker. */ con_str = log_str = ""; } if (con_file != NULL) fputs(con_str, con_file); if (log_file != NULL) fputs(log_str, log_file); } /* * Application-defined progress update callback. */ static void app_progress(unsigned long current_step, unsigned long total_steps) { /* There will be a potentially long wait, so flush the console output. */ if (con_file != NULL) fflush(con_file); /* An eager flush of the line-buffered log file is not very important. */ /* A GUI application would normally update a progress bar. */ /* Here we ignore the progress info. */ if (current_step && total_steps) return; } /* * Application initialization. */ static void app_init(void) { start_of_line = 1; if (operation == OP_SHOW_HELP || operation == OP_SHOW_VERSION) con_file = stdout; else if (!options.quiet) con_file = stderr; else con_file = NULL; if (options.log_name != NULL) { /* Open the log file, line-buffered. */ if ((log_file = fopen(options.log_name, "a")) == NULL) error("Can't open log file: %s\n", options.log_name); setvbuf(log_file, NULL, _IOLBF, BUFSIZ); app_printf("** Warning: %s\n\n", "The option -log is deprecated; use shell redirection"); } } /* * Application finalization. */ static void app_finish(void) { if (log_file != NULL) { /* Close the log file. */ fclose(log_file); } } /* * File list processing. */ static int process_files(int argc, char *argv[]) { int result; struct opng_ui ui; int i; /* Initialize the optimization engine. */ ui.printf_fn = app_printf; ui.print_cntrl_fn = app_print_cntrl; ui.progress_fn = app_progress; ui.panic_fn = panic; if (opng_initialize(&options, &ui) != 0) panic("Can't initialize optimization engine"); /* Iterate over file names. */ result = EXIT_SUCCESS; for (i = 1; i < argc; ++i) { if (argv[i] == NULL || argv[i][0] == 0) continue; /* this was an "-option" */ if (opng_optimize(argv[i]) != 0) result = EXIT_FAILURE; } /* Finalize the optimization engine. */ if (opng_finalize() != 0) panic("Can't finalize optimization engine"); return result; } /* * The main function. */ int main(int argc, char *argv[]) { int result; /* Parse the user options and initialize the application. */ parse_args(argc, argv); app_init(); result = EXIT_SUCCESS; if (local_options.version) { /* Print the copyright and version info. */ app_printf("%s\n", msg_intro); } switch (operation) { case OP_RUN: /* Run the application. */ result = process_files(argc, argv); break; case OP_SHOW_HELP: if (local_options.help) { /* Print the extended help text. */ app_printf("%s%s%s", msg_help_synopsis, msg_help_options, msg_help_examples); } else { /* Print the basic help text. */ app_printf("%s%s%s%s", msg_help_synopsis, msg_help_basic_options, msg_help_examples, msg_help_more); } break; case OP_SHOW_VERSION: /* Print the licensing terms and the extended version info. */ app_printf("%s\n", msg_license); app_printf("Using libpng version %s and zlib version %s\n", png_get_libpng_ver(NULL), zlibVersion()); break; default: result = -1; } /* Finalize the application. */ app_finish(); return result; } optipng-0.7.7/src/optipng/optipng.h000066400000000000000000000044451343170417500173210ustar00rootroot00000000000000/* * optipng.h * The OptiPNG programming interface. * * Copyright (C) 2001-2017 Cosmin Truta and the Contributing Authors. * * This software is distributed under the zlib license. * Please see the accompanying LICENSE file. */ #ifndef OPTIPNG_H_ #define OPTIPNG_H_ #include "bitset.h" #ifdef __cplusplus extern "C" { #endif /* * User options. */ struct opng_options { /* General options. */ int backup; int clobber; int debug; int fix; int force; int full; int preserve; int quiet; int simulate; int verbose; const char *out_name; const char *dir_name; const char *log_name; /* Optimization options. */ int interlace; int nb, nc, np, nz; int optim_level; opng_bitset_t compr_level_set; opng_bitset_t mem_level_set; opng_bitset_t strategy_set; opng_bitset_t filter_set; int window_bits; /* Editing options. */ int snip; int strip_all; }; /* * User interface callbacks. */ struct opng_ui { void (*printf_fn)(const char *fmt, ...); void (*print_cntrl_fn)(int cntrl_code); void (*progress_fn)(unsigned long current_step, unsigned long total_steps); void (*panic_fn)(const char *msg); }; /* * Engine initialization. */ int opng_initialize(const struct opng_options *options, const struct opng_ui *ui); /* * Engine execution. */ int opng_optimize(const char *infile_name); /* * Engine finalization. */ int opng_finalize(void); /* * Encoder limits and default values. */ #define OPNG_OPTIM_LEVEL_DEFAULT 2 #define OPNG_OPTIM_LEVEL_MIN 0 #define OPNG_OPTIM_LEVEL_MAX 7 #define OPNG_COMPR_LEVEL_MIN 1 #define OPNG_COMPR_LEVEL_MAX 9 #define OPNG_COMPR_LEVEL_SET_MASK ((1 << (9+1)) - (1 << 1)) /* 0x03fe */ #define OPNG_MEM_LEVEL_MIN 1 #define OPNG_MEM_LEVEL_MAX 9 #define OPNG_MEM_LEVEL_SET_MASK ((1 << (9+1)) - (1 << 1)) /* 0x03fe */ #define OPNG_STRATEGY_MIN 0 #define OPNG_STRATEGY_MAX 3 #define OPNG_STRATEGY_SET_MASK ((1 << (3+1)) - (1 << 0)) /* 0x000f */ #define OPNG_FILTER_MIN 0 #define OPNG_FILTER_MAX 5 #define OPNG_FILTER_SET_MASK ((1 << (5+1)) - (1 << 0)) /* 0x003f */ #ifdef __cplusplus } /* extern "C" */ #endif #endif /* OPTIPNG_H_ */ optipng-0.7.7/src/optipng/proginfo.h000066400000000000000000000011321343170417500174520ustar00rootroot00000000000000/* * proginfo.h * OptiPNG program information. * * Copyright (C) 2001-2017 Cosmin Truta and the Contributing Authors. * * This software is distributed under the zlib license. * Please see the accompanying LICENSE file. */ #ifndef PROGINFO_H_ #define PROGINFO_H_ #define PROGRAM_NAME \ "OptiPNG" #define PROGRAM_SUMMARY \ "Portable Network Graphics optimizer" #define PROGRAM_VERSION \ "0.7.7" #define PROGRAM_COPYRIGHT \ "Copyright (C) 2001-2017 Cosmin Truta and the Contributing Authors" #define PROGRAM_URI \ "http://optipng.sourceforge.net/" #endif /* PROGINFO_H_ */ optipng-0.7.7/src/optipng/ratio.c000066400000000000000000000147431343170417500167540ustar00rootroot00000000000000/* * ratio.c * Exact rational numbers. * * Copyright (C) 2003-2017 Cosmin Truta. * * This software is distributed under the zlib license. * Please see the accompanying LICENSE file. */ #include "ratio.h" #include #include #include #include #ifdef OPNG_LLONG_T_DEFINED typedef opng_llong_t opng_xlong_impl_t; typedef opng_ullong_t opng_uxlong_impl_t; #define OPNG_XLONG_IMPL_FORMAT_PREFIX OPNG_LLONG_FORMAT_PREFIX #else typedef long opng_xlong_impl_t; typedef unsigned long opng_uxlong_impl_t; #define OPNG_XLONG_IMPL_FORMAT_PREFIX "l" #endif /* * Writes formatted output to a memory buffer. * This is a wrapper to [v]snprintf which avoids well-known defects * occurring in some of the underlying snprintf implementations. * The function returns the number of characters written, excluding the * null-termination character, if the buffer size is large enough, or -1 * otherwise. (Unlike the proper snprintf, this function does not return * a number larger than zero if the buffer size is too small.) */ static int opng_snprintf_impl(char *buffer, size_t buffer_size, const char *format, ...) { #if defined _WIN32 || defined __WIN32__ || defined _WIN64 || defined __WIN64__ #define OPNG_VSNPRINTF _vsnprintf #else #define OPNG_VSNPRINTF vsnprintf #endif va_list arg_ptr; int result; va_start(arg_ptr, format); result = OPNG_VSNPRINTF(buffer, buffer_size, format, arg_ptr); va_end(arg_ptr); if (result < 0 || (size_t)result >= buffer_size) { /* Guard against broken [v]snprintf implementations. */ if (buffer_size > 0) buffer[buffer_size - 1] = '\0'; return -1; } return result; #undef OPNG_VSNPRINTF } /* * Writes a decomposed rational value to a memory buffer. * This is the base implementation used internally by the the other * ratio-to-string conversion functions. */ static int opng_sprint_uratio_impl(char *buffer, size_t buffer_size, opng_uxlong_impl_t num, opng_uxlong_impl_t denom, int always_percent) { /* (1) num/denom == 0/0 ==> print "??%" * (2) num/denom == INFINITY ==> print "INFINITY%" * (3) 0 <= num/denom < 99.995% ==> use the percent format "99.99%" * if always_percent: * (4) 0.995 <= num/denom < INFINITY ==> use the percent format "999%" * else: * (5) 0.995 <= num/denom < 99.995 ==> use the factor format "9.99x" * (6) 99.5 <= num/denom < INFINITY ==> use the factor format "999x" * end if */ opng_uxlong_impl_t integer_part, remainder; unsigned int fractional_part, scale; double scaled_ratio; /* (1,2): num/denom == 0/0 or num/denom == INFINITY */ if (denom == 0) return opng_snprintf_impl(buffer, buffer_size, num == 0 ? "??%%" : "INFINITY%%"); /* (3): 0 <= num/denom < 99.995% */ /* num/denom < 99.995% <==> denom/(denom-num) < 20000 */ if (num < denom && denom / (denom - num) < 20000) { scale = 10000; scaled_ratio = ((double)num * (double)scale) / (double)denom; fractional_part = (unsigned int)(scaled_ratio + 0.5); /* Adjust the scaled result in the event of a roundoff error. */ /* Such error may occur only if the numerator is extremely large. */ if (fractional_part >= scale) fractional_part = scale - 1; return opng_snprintf_impl(buffer, buffer_size, "%u.%02u%%", fractional_part / 100, fractional_part % 100); } /* Extract the integer part out of the fraction for the remaining cases. */ integer_part = num / denom; remainder = num % denom; scale = 100; scaled_ratio = ((double)remainder * (double)scale) / (double)denom; fractional_part = (unsigned int)(scaled_ratio + 0.5); if (fractional_part >= scale) { fractional_part = 0; ++integer_part; } /* (4): 0.995 <= num/denom < INFINITY */ if (always_percent) return opng_snprintf_impl(buffer, buffer_size, "%" OPNG_XLONG_IMPL_FORMAT_PREFIX "u%02u%%", integer_part, fractional_part); /* (5): 0.995 <= num/denom < 99.995 */ if (integer_part < 100) return opng_snprintf_impl(buffer, buffer_size, "%" OPNG_XLONG_IMPL_FORMAT_PREFIX "u.%02ux", integer_part, fractional_part); /* (6): 99.5 <= num/denom < INFINITY */ /* Round to the nearest integer. */ /* Recalculate the integer part, for corner cases like 123.999. */ integer_part = num / denom; if (remainder > (denom - 1) / 2) ++integer_part; return opng_snprintf_impl(buffer, buffer_size, "%" OPNG_XLONG_IMPL_FORMAT_PREFIX "ux", integer_part); } /* * Converts a rational value to a compact factor string representation. */ int opng_ulratio_to_factor_string(char *buffer, size_t buffer_size, const struct opng_ulratio *ratio) { opng_uxlong_impl_t num = ratio->num; opng_uxlong_impl_t denom = ratio->denom; return opng_sprint_uratio_impl(buffer, buffer_size, num, denom, 0); } /* * Converts a rational value to a compact percent string representation. */ int opng_ulratio_to_percent_string(char *buffer, size_t buffer_size, const struct opng_ulratio *ratio) { opng_uxlong_impl_t num = ratio->num; opng_uxlong_impl_t denom = ratio->denom; return opng_sprint_uratio_impl(buffer, buffer_size, num, denom, 1); } #ifdef OPNG_LLONG_T_DEFINED /* * Converts a rational value to a compact factor string representation. */ int opng_ullratio_to_factor_string(char *buffer, size_t buffer_size, const struct opng_ullratio *ratio) { opng_uxlong_impl_t num = ratio->num; opng_uxlong_impl_t denom = ratio->denom; return opng_sprint_uratio_impl(buffer, buffer_size, num, denom, 0); } /* * Converts a rational value to a compact percent string representation. */ int opng_ullratio_to_percent_string(char *buffer, size_t buffer_size, const struct opng_ullratio *ratio) { opng_uxlong_impl_t num = ratio->num; opng_uxlong_impl_t denom = ratio->denom; return opng_sprint_uratio_impl(buffer, buffer_size, num, denom, 1); } #endif /* OPNG_LLONG_T_DEFINED */ optipng-0.7.7/src/optipng/ratio.h000066400000000000000000000103651343170417500167550ustar00rootroot00000000000000/* * ratio.h * Exact rational numbers. * * Copyright (C) 2003-2017 Cosmin Truta. * * This software is distributed under the zlib license. * Please see the accompanying LICENSE file. */ #ifndef OPNG_RATIO_H_ #define OPNG_RATIO_H_ #include /* * The following definitions exist for the benefit of pre-C99 and pre-C++11 * compilers and runtimes that are unable to grok the long long type. */ #ifndef OPNG_LLONG_T_DEFINED #include #if defined LLONG_MAX && defined ULLONG_MAX #if (LLONG_MAX >= LONG_MAX) && (ULLONG_MAX >= ULONG_MAX) typedef long long opng_llong_t; typedef unsigned long long opng_ullong_t; #define OPNG_LLONG_MIN LLONG_MIN #define OPNG_LLONG_MAX LLONG_MAX #define OPNG_ULLONG_MAX ULLONG_MAX #define OPNG_LLONG_C(value) value##LL #define OPNG_ULLONG_C(value) value##ULL #define OPNG_LLONG_T_DEFINED 1 #endif #elif defined _I64_MAX && defined _UI64_MAX #if defined _WIN32 || defined __WIN32__ typedef __int64 opng_llong_t; typedef unsigned __int64 opng_ullong_t; #define OPNG_LLONG_MIN _I64_MIN #define OPNG_LLONG_MAX _I64_MAX #define OPNG_ULLONG_MAX _UI64_MAX #define OPNG_LLONG_C(value) value##i64 #define OPNG_ULLONG_C(value) value##ui64 #define OPNG_LLONG_T_DEFINED 1 #endif #endif #ifdef OPNG_LLONG_T_DEFINED #if defined _WIN32 || defined __WIN32__ /* The "ll" format modifier may not work on Windows XP and earlier. */ #define OPNG_LLONG_FORMAT_PREFIX "I64" #else #define OPNG_LLONG_FORMAT_PREFIX "ll" #endif #endif #endif /* OPNG_LLONG_T_DEFINED */ #ifdef __cplusplus extern "C" { #endif /* * The long rational type. */ struct opng_lratio { long num; long denom; }; /* * The unsigned long rational type. */ struct opng_ulratio { unsigned long num; unsigned long denom; }; #ifdef OPNG_LLONG_T_DEFINED /* * The long long rational type. */ struct opng_llratio { opng_llong_t num; opng_llong_t denom; }; /* * The unsigned long long rational type. */ struct opng_ullratio { opng_ullong_t num; opng_ullong_t denom; }; #endif /* OPNG_LLONG_T_DEFINED */ /* * Converts a rational value to a compact factor string representation. * Examples: 34/55 -> "61.82%", 55/34 -> "1.62x". * * The factor string has the following format: * * "DD.DD%" if ratio < 99.995% * "DD.DDx" if ratio >= 99.995% and ratio < 99.995 * "DDDx" if ratio >= 99.995 * "??%" if ratio == 0/0 * "INFINITY%" if ratio >= 1/0 * * The buffer shall contain the output string, or a part of it if the * buffer size is too small, always null-terminated. * The function shall return the number of characters stored, not including * the null-character terminator, or -1 if the buffer size is too small. */ int opng_ulratio_to_factor_string(char *buffer, size_t buffer_size, const struct opng_ulratio *ratio); /* * Converts a rational value to a compact percent string representation. * Examples: 34/55 -> "61.82%", 55/34 -> "162%". * * This is the format "DD.DD%" for ratios below 99.995%, and the format * "DDD%" for ratios equal to or above 99.995%. * * The buffer shall contain the output string, or a part of it if the * buffer size is too small, always null-terminated. * The function shall return the number of characters stored, not including * the null-character terminator, or -1 if the buffer size is too small. */ int opng_ulratio_to_percent_string(char *buffer, size_t buffer_size, const struct opng_ulratio *ratio); #ifdef OPNG_LLONG_T_DEFINED /* * Converts a rational value to a compact factor string representation. * See opng_ulratio_to_factor_string. */ int opng_ullratio_to_factor_string(char *buffer, size_t buffer_size, const struct opng_ullratio *ratio); /* * Converts a rational value to a compact percent string representation. * See opng_ulratio_to_percent_string. */ int opng_ullratio_to_percent_string(char *buffer, size_t buffer_size, const struct opng_ullratio *ratio); #endif /* OPNG_LLONG_T_DEFINED */ /* * TODO: * opng_[l,ll]ratio_to_factor_string * opng_[l,ul,ll,ull]ratio_to_factor_wstring * opng_[l,ll]ratio_to_percent_string * opng_[l,ul,ll,ull]ratio_to_percent_wstring */ #ifdef __cplusplus } /* extern "C" */ #endif #endif /* OPNG_RATIO_H_ */ optipng-0.7.7/src/optipng/test/000077500000000000000000000000001343170417500164405ustar00rootroot00000000000000optipng-0.7.7/src/optipng/test/bitset_test.c000066400000000000000000000402561343170417500211440ustar00rootroot00000000000000/* * bitset_test.c * Test for bitset. * * Copyright (C) 2001-2017 Cosmin Truta. * * This software is distributed under the zlib license. * Please see the accompanying LICENSE file. */ #include "bitset.h" #include #include #include static int num_tests = 0; static int num_errors = 0; #define EMPTY OPNG_BITSET_EMPTY #define FULL OPNG_BITSET_FULL #define ELT_MIN OPNG_BITSET_ELT_MIN #define ELT_MAX OPNG_BITSET_ELT_MAX #define TEST_BOOL(expr) \ test_int_impl("!!(" #expr ")", !!(expr), 1) #define TEST_INT(expr, expected) \ test_int_impl(#expr, expr, expected) #define TEST_BITSET(expr, expected) \ test_bitset_impl(#expr, expr, expected) static void test_int_impl(const char *expr_str, int result, int expected) { ++num_tests; if (result != expected) { ++num_errors; printf("FAILED: %s, result: %d, expected: %d\n", expr_str, result, expected); } } static void test_bitset_impl(const char *expr_str, opng_bitset_t result, opng_bitset_t expected) { ++num_tests; if (result != expected) { ++num_errors; printf("FAILED: %s, result: 0x%lx, expected: 0x%lx\n", expr_str, (unsigned long)result, (unsigned long)expected); } } static void test_bitset_const() { printf("Testing: bitset constants\n"); TEST_BITSET(EMPTY, 0); TEST_BITSET(FULL, ~EMPTY); TEST_INT(ELT_MIN, 0); TEST_INT(ELT_MAX, (int)OPNG_BITSIZEOF(opng_bitset_t) - 1); TEST_INT(ELT_MAX, (int)(sizeof(opng_bitset_t) * CHAR_BIT) - 1); } static void test_bitset_obs() { printf("Testing: bitset observers\n"); TEST_INT(opng_bitset_test(EMPTY, ELT_MIN), 0); TEST_INT(opng_bitset_test(EMPTY, ELT_MAX), 0); TEST_INT(opng_bitset_test(FULL, ELT_MIN), 1); TEST_INT(opng_bitset_test(FULL, ELT_MAX), 1); TEST_INT(opng_bitset_test(0x0002, ELT_MIN), 0); TEST_INT(opng_bitset_test(0x0ff0, ELT_MAX), 0); TEST_INT(opng_bitset_test(EMPTY, 1), 0); TEST_INT(opng_bitset_test(FULL, 1), 1); TEST_INT(opng_bitset_test(0x0002, 1), 1); TEST_INT(opng_bitset_test(0x0ff0, 1), 0); TEST_INT(opng_bitset_test_all_in_range(EMPTY, ELT_MIN, ELT_MAX), 0); TEST_INT(opng_bitset_test_all_in_range(FULL, ELT_MIN, ELT_MAX), 1); TEST_INT(opng_bitset_test_all_in_range(0x0002, ELT_MIN, ELT_MAX), 0); TEST_INT(opng_bitset_test_all_in_range(0x0ff0, ELT_MIN, ELT_MAX), 0); TEST_INT(opng_bitset_test_all_in_range(EMPTY, 1, 1), 0); TEST_INT(opng_bitset_test_all_in_range(FULL, 1, 1), 1); TEST_INT(opng_bitset_test_all_in_range(0x0002, 1, 1), 1); TEST_INT(opng_bitset_test_all_in_range(0x0ff0, 1, 1), 0); TEST_INT(opng_bitset_test_any_in_range(EMPTY, ELT_MIN, ELT_MAX), 0); TEST_INT(opng_bitset_test_any_in_range(FULL, ELT_MIN, ELT_MAX), 1); TEST_INT(opng_bitset_test_any_in_range(0x0002, ELT_MIN, ELT_MAX), 1); TEST_INT(opng_bitset_test_any_in_range(0x0ff0, ELT_MIN, ELT_MAX), 1); TEST_INT(opng_bitset_test_any_in_range(EMPTY, 1, 1), 0); TEST_INT(opng_bitset_test_any_in_range(FULL, 1, 1), 1); TEST_INT(opng_bitset_test_any_in_range(0x0002, 1, 1), 1); TEST_INT(opng_bitset_test_any_in_range(0x0ff0, 1, 1), 0); TEST_INT(opng_bitset_count(EMPTY), 0); TEST_INT(opng_bitset_count(FULL), OPNG_BITSIZEOF(opng_bitset_t)); TEST_INT(opng_bitset_count(0x0002), 1); TEST_INT(opng_bitset_count(0x0ff0), 8); } static void test_bitset_mod() { opng_bitset_t set; printf("Testing: bitset modifiers\n"); set = 0x0002; opng_bitset_set(&set, 1); opng_bitset_set(&set, 2); TEST_BITSET(set, 0x06); opng_bitset_reset(&set, 2); opng_bitset_reset(&set, 3); TEST_BITSET(set, 0x0002); opng_bitset_flip(&set, 3); opng_bitset_flip(&set, 1); TEST_BITSET(set, 0x08); set = 0x0ff0; opng_bitset_set_range(&set, 0, 7); TEST_BITSET(set, 0x0fff); opng_bitset_set_range(&set, ELT_MIN, ELT_MAX); TEST_BITSET(set, FULL); set = 0x0ff0; opng_bitset_reset_range(&set, 0, 7); TEST_BITSET(set, 0x0f00); opng_bitset_reset_range(&set, ELT_MIN, ELT_MAX); TEST_BITSET(set, EMPTY); set = 0x0ff0; opng_bitset_flip_range(&set, 0, 7); TEST_BITSET(set, 0x0f0f); opng_bitset_flip_range(&set, ELT_MIN, ELT_MAX); TEST_BITSET(set, FULL ^ 0x0f0f); } static void test_bitset_find_forward_impl(opng_bitset_t bitset) { opng_bitset_t check_bitset; int check_count; int elt, prev_elt; check_bitset = EMPTY; check_count = 0; prev_elt = -1; for (elt = opng_bitset_find_first(bitset); elt >= 0; elt = opng_bitset_find_next(bitset, elt)) { if (elt < ELT_MIN || elt > ELT_MAX || elt <= prev_elt) { /* Fail. */ TEST_INT(check_count, -1); return; } opng_bitset_set(&check_bitset, elt); ++check_count; prev_elt = elt; } TEST_BITSET(check_bitset, bitset); TEST_INT(check_count, opng_bitset_count(bitset)); } static void test_bitset_find_reverse_impl(opng_bitset_t bitset) { opng_bitset_t check_bitset; int check_count; int elt, prev_elt; check_bitset = EMPTY; check_count = 0; prev_elt = INT_MAX; for (elt = opng_bitset_find_last(bitset); elt >= 0; elt = opng_bitset_find_prev(bitset, elt)) { if (elt < ELT_MIN || elt > ELT_MAX || elt >= prev_elt) { /* Fail. */ TEST_INT(check_count, -1); return; } opng_bitset_set(&check_bitset, elt); ++check_count; prev_elt = elt; } TEST_BITSET(check_bitset, bitset); TEST_INT(check_count, opng_bitset_count(bitset)); } static void test_bitset_iter() { printf("Testing: bitset iterators\n"); TEST_INT(opng_bitset_find_first(EMPTY), -1); TEST_INT(opng_bitset_find_first(FULL), ELT_MIN); TEST_INT(opng_bitset_find_first(0x0002), 1); TEST_INT(opng_bitset_find_first(0x0ff0), 4); TEST_INT(opng_bitset_find_next(EMPTY, 0), -1); TEST_INT(opng_bitset_find_next(FULL, 0), 1); TEST_INT(opng_bitset_find_next(0x0002, 0), 1); TEST_INT(opng_bitset_find_next(0x0ff0, 0), 4); TEST_INT(opng_bitset_find_next(EMPTY, 1), -1); TEST_INT(opng_bitset_find_next(FULL, 1), 2); TEST_INT(opng_bitset_find_next(0x0002, 1), -1); TEST_INT(opng_bitset_find_next(0x0ff0, 1), 4); TEST_INT(opng_bitset_find_next(EMPTY, 2), -1); TEST_INT(opng_bitset_find_next(FULL, 2), 3); TEST_INT(opng_bitset_find_next(0x0002, 2), -1); TEST_INT(opng_bitset_find_next(0x0ff0, 2), 4); TEST_INT(opng_bitset_find_next(EMPTY, ELT_MAX), -1); TEST_INT(opng_bitset_find_next(FULL, ELT_MAX), -1); TEST_INT(opng_bitset_find_next(0x0002, ELT_MAX), -1); TEST_INT(opng_bitset_find_next(0x0ff0, ELT_MAX), -1); TEST_INT(opng_bitset_find_last(EMPTY), -1); TEST_INT(opng_bitset_find_last(FULL), ELT_MAX); TEST_INT(opng_bitset_find_last(0x0002), 1); TEST_INT(opng_bitset_find_last(0x0ff0), 11); TEST_INT(opng_bitset_find_prev(EMPTY, 0), -1); TEST_INT(opng_bitset_find_prev(FULL, 0), -1); TEST_INT(opng_bitset_find_prev(0x0002, 0), -1); TEST_INT(opng_bitset_find_prev(0x0ff0, 0), -1); TEST_INT(opng_bitset_find_prev(EMPTY, 1), -1); TEST_INT(opng_bitset_find_prev(FULL, 1), 0); TEST_INT(opng_bitset_find_prev(0x0002, 1), -1); TEST_INT(opng_bitset_find_prev(0x0ff0, 1), -1); TEST_INT(opng_bitset_find_prev(EMPTY, 2), -1); TEST_INT(opng_bitset_find_prev(FULL, 2), 1); TEST_INT(opng_bitset_find_prev(0x0002, 2), 1); TEST_INT(opng_bitset_find_prev(0x0ff0, 2), -1); TEST_INT(opng_bitset_find_prev(EMPTY, ELT_MAX), -1); TEST_INT(opng_bitset_find_prev(FULL, ELT_MAX), ELT_MAX - 1); TEST_INT(opng_bitset_find_prev(0x0002, ELT_MAX), 1); TEST_INT(opng_bitset_find_prev(0x0ff0, ELT_MAX), 11); test_bitset_find_forward_impl(EMPTY); test_bitset_find_forward_impl(FULL); test_bitset_find_forward_impl(0x0002); test_bitset_find_forward_impl(0x0ff0); test_bitset_find_reverse_impl(EMPTY); test_bitset_find_reverse_impl(FULL); test_bitset_find_reverse_impl(0x0002); test_bitset_find_reverse_impl(0x0ff0); } static void test_strparse_rangeset_impl(const char *rangeset, opng_bitset_t mask, opng_bitset_t expected_bitset, int expected_errno) { opng_bitset_t bitset; int parse_result, expected_parse_result; ++num_tests; errno = 0; expected_parse_result = (expected_errno == 0) ? 0 : -1; parse_result = opng_strparse_rangeset_to_bitset(&bitset, rangeset, mask); if (parse_result != expected_parse_result || bitset != expected_bitset || errno != expected_errno) { ++num_errors; printf("FAILED: opng_strparse_rangeset_to_bitset(\"%s\", 0x%lx)\n", rangeset, (unsigned long)mask); printf(" bitset: 0x%lx, expected: 0x%lx\n", (unsigned long)bitset, (unsigned long)expected_bitset); printf(" result: %d, expected: %d\n", parse_result, expected_parse_result); printf(" errno: %d, expected: %d\n", errno, expected_errno); } } static void test_rangeset_parse() { static const opng_bitset_t mask_full = FULL; static const opng_bitset_t mask_byte = 0x00ff; static const opng_bitset_t mask_pattern = 0x5555; static const opng_bitset_t mask_empty = EMPTY; printf("Testing: rangeset parser\n"); test_strparse_rangeset_impl("", mask_full, EMPTY, 0); test_strparse_rangeset_impl(" ", mask_byte, EMPTY, 0); test_strparse_rangeset_impl(" ", mask_pattern, EMPTY, 0); test_strparse_rangeset_impl(" ,; ;, ", mask_empty, EMPTY, 0); test_strparse_rangeset_impl("0", mask_full, 0x0001, 0); test_strparse_rangeset_impl("0,", mask_byte, 0x0001, 0); test_strparse_rangeset_impl(",0", mask_pattern, 0x0001, 0); test_strparse_rangeset_impl(",0,", mask_empty, FULL, ERANGE); test_strparse_rangeset_impl("0-", mask_full, FULL, 0); test_strparse_rangeset_impl("0-;", mask_pattern, 0x5555, 0); test_strparse_rangeset_impl(";0-", mask_byte, 0x00ff, 0); test_strparse_rangeset_impl(";0-;", mask_empty, FULL, ERANGE); test_strparse_rangeset_impl(" 01 ", mask_full, 0x0002, 0); test_strparse_rangeset_impl(" 01,; ", mask_byte, 0x0002, 0); test_strparse_rangeset_impl(" ,;01 ", mask_pattern, FULL, ERANGE); test_strparse_rangeset_impl(" ,;01,; ", mask_empty, FULL, ERANGE); test_strparse_rangeset_impl(" 012 , ;", mask_full, 0x1000, 0); test_strparse_rangeset_impl(", ; 012 ", mask_byte, FULL, ERANGE); test_strparse_rangeset_impl(",;012,;", mask_pattern, 0x1000, 0); test_strparse_rangeset_impl("1, 1", mask_full, 0x0002, 0); test_strparse_rangeset_impl("1- 1", mask_byte, 0x0002, 0); test_strparse_rangeset_impl("1 ;2", mask_full, 0x0006, 0); test_strparse_rangeset_impl("1 -2", mask_byte, 0x0006, 0); test_strparse_rangeset_impl("1 - 2", mask_pattern, FULL, ERANGE); test_strparse_rangeset_impl("2-1", mask_full, FULL, ERANGE); test_strparse_rangeset_impl("2-1", mask_byte, FULL, ERANGE); test_strparse_rangeset_impl("124", mask_full, FULL, ERANGE); test_strparse_rangeset_impl("12-4", mask_full, FULL, ERANGE); test_strparse_rangeset_impl("1-2,4", mask_full, 0x0016, 0); test_strparse_rangeset_impl("1-2,4-", mask_byte, 0x00f6, 0); test_strparse_rangeset_impl("1,2,4", mask_full, 0x0016, 0); test_strparse_rangeset_impl("1,2,4-", mask_pattern, FULL, ERANGE); test_strparse_rangeset_impl("1,2,4", mask_byte, 0x0016, 0); test_strparse_rangeset_impl("1,2-4", mask_full, 0x001e, 0); test_strparse_rangeset_impl("12,4", mask_full, 0x1010, 0); test_strparse_rangeset_impl("12,4", mask_byte, FULL, ERANGE); test_strparse_rangeset_impl("2-4,1", mask_full, 0x001e, 0); test_strparse_rangeset_impl("4-2,1", mask_full, FULL, ERANGE); test_strparse_rangeset_impl("4-,2-1", mask_byte, FULL, ERANGE); test_strparse_rangeset_impl("4-,1-2", mask_full, FULL ^ 0x0009, 0); test_strparse_rangeset_impl("9999999999", mask_full, FULL, ERANGE); test_strparse_rangeset_impl("9999999999-", mask_byte, FULL, ERANGE); test_strparse_rangeset_impl("-", mask_full, EMPTY, EINVAL); test_strparse_rangeset_impl(" - ", mask_pattern, EMPTY, EINVAL); test_strparse_rangeset_impl("--", mask_byte, EMPTY, EINVAL); test_strparse_rangeset_impl("- -", mask_empty, EMPTY, EINVAL); test_strparse_rangeset_impl("0--", mask_full, EMPTY, EINVAL); test_strparse_rangeset_impl("0 -- ", mask_pattern, EMPTY, EINVAL); test_strparse_rangeset_impl("0- -", mask_byte, EMPTY, EINVAL); test_strparse_rangeset_impl("0 --- ", mask_empty, EMPTY, EINVAL); test_strparse_rangeset_impl("-0", mask_full, EMPTY, EINVAL); test_strparse_rangeset_impl("-0-", mask_pattern, EMPTY, EINVAL); test_strparse_rangeset_impl("1k", mask_full, EMPTY, EINVAL); test_strparse_rangeset_impl("1 k", mask_pattern, EMPTY, EINVAL); test_strparse_rangeset_impl("A1", mask_full, EMPTY, EINVAL); test_strparse_rangeset_impl("0xA1", mask_pattern, EMPTY, EINVAL); test_strparse_rangeset_impl(".1", mask_full, EMPTY, EINVAL); test_strparse_rangeset_impl("1.", mask_pattern, EMPTY, EINVAL); test_strparse_rangeset_impl("1.2", mask_byte, EMPTY, EINVAL); test_strparse_rangeset_impl("1 2", mask_full, EMPTY, EINVAL); test_strparse_rangeset_impl("2 1", mask_pattern, EMPTY, EINVAL); test_strparse_rangeset_impl("1--2", mask_full, EMPTY, EINVAL); test_strparse_rangeset_impl("1--2-", mask_pattern, EMPTY, EINVAL); test_strparse_rangeset_impl("1- -2", mask_byte, EMPTY, EINVAL); test_strparse_rangeset_impl("1- -2-", mask_empty, EMPTY, EINVAL); test_strparse_rangeset_impl("-1--2", mask_full, EMPTY, EINVAL); test_strparse_rangeset_impl("-1--2-", mask_pattern, EMPTY, EINVAL); test_strparse_rangeset_impl("-1- -2", mask_byte, EMPTY, EINVAL); test_strparse_rangeset_impl("-1- -2-", mask_empty, EMPTY, EINVAL); test_strparse_rangeset_impl("1-2-4", mask_full, EMPTY, EINVAL); test_strparse_rangeset_impl("1-2-4-", mask_pattern, EMPTY, EINVAL); test_strparse_rangeset_impl("1-2-4-", mask_byte, EMPTY, EINVAL); test_strparse_rangeset_impl("-1-2-4", mask_empty, EMPTY, EINVAL); test_strparse_rangeset_impl("1-4-2,", mask_full, EMPTY, EINVAL); test_strparse_rangeset_impl("1-4-2-,", mask_pattern, EMPTY, EINVAL); test_strparse_rangeset_impl("1-4-2-,", mask_byte, EMPTY, EINVAL); test_strparse_rangeset_impl("-1-4-2,", mask_empty, EMPTY, EINVAL); test_strparse_rangeset_impl(",4-2-1;", mask_full, EMPTY, EINVAL); test_strparse_rangeset_impl(",4-2-1-;", mask_pattern, EMPTY, EINVAL); test_strparse_rangeset_impl(",4-2-1-;", mask_byte, EMPTY, EINVAL); test_strparse_rangeset_impl(",-4-2-1;", mask_empty, EMPTY, EINVAL); test_strparse_rangeset_impl("-9999999999", mask_full, EMPTY, EINVAL); } static void run_tests() { test_bitset_const(); test_bitset_obs(); test_bitset_mod(); test_bitset_iter(); test_rangeset_parse(); } int main() { run_tests(); if (num_errors != 0) { printf("** %d/%d tests FAILED **\n", num_errors, num_tests); return 1; } else { printf("** %d tests passed **\n", num_tests); return 0; } } optipng-0.7.7/src/optipng/test/ratio_test.c000066400000000000000000000226671343170417500207760ustar00rootroot00000000000000/* * ratio_test.c * Test for ratio. * * Copyright (C) 2008-2017 Cosmin Truta. * * This software is distributed under the zlib license. * Please see the accompanying LICENSE file. */ #include "ratio.h" #include #include #include #include #if !defined(OPNG_ULLONG_MAX) || !defined(OPNG_ULLONG_C) #error Missing opng_ullong_t macros #endif #if OPNG_ULLONG_MAX != ~OPNG_ULLONG_C(0) #error Incorrect opng_ullong_t macros #endif static int num_tests = 0; static int num_errors = 0; #define U32_MAX 0xffffffffUL #define ULL_MAX OPNG_ULLONG_MAX #define BUFFER_SIZE 64 typedef int (*ulconv_func_t)(char *buffer, size_t buffer_size, const struct opng_ulratio *ratio); typedef int (*ullconv_func_t)(char *buffer, size_t buffer_size, const struct opng_ullratio *ratio); static int do_conv(ulconv_func_t ulconv, ullconv_func_t ullconv, char *buffer, size_t buffer_size, opng_ullong_t num, opng_ullong_t denom) { char replica_buffer[BUFFER_SIZE]; struct opng_ulratio ulratio; struct opng_ullratio ullratio; int ulresult, ullresult; ullratio.num = num; ullratio.denom = denom; ullresult = ullconv(buffer, buffer_size, &ullratio); if (ullresult >= 0 && strlen(buffer) != (size_t)ullresult) { fprintf(stderr, "Can't handle incorrect output strings\n."); abort(); } #if OPNG_ULLONG_MAX > ULONG_MAX /* Replicate the result only if the input can be narrowed correctly. */ if ((unsigned long)num != num || (unsigned long)denom != denom) return ullresult; #endif ulratio.num = (unsigned long)num; ulratio.denom = (unsigned long)denom; ulresult = ulconv(replica_buffer, buffer_size, &ulratio); if (ulresult != ullresult || (ulresult >= 0 && strcmp(replica_buffer, buffer) != 0)) { fprintf(stderr, "Can't handle inconsistent output strings.\n"); abort(); } return ullresult; } static void test_conv(ulconv_func_t ulconv, ullconv_func_t ullconv, char *buffer, size_t buffer_size, opng_ullong_t num, opng_ullong_t denom) { char check_buffer[BUFFER_SIZE]; size_t exact_buffer_size; int conv_result; conv_result = do_conv(ulconv, ullconv, buffer, buffer_size, num, denom); if (conv_result <= 0) { fprintf(stderr, "Can't test; a larger buffer is required.\n"); abort(); } exact_buffer_size = (size_t)conv_result + 1; if (do_conv(ulconv, ullconv, check_buffer, exact_buffer_size, num, denom) != conv_result) { fprintf(stderr, "Can't handle buffers of exact size.\n"); abort(); } if (do_conv(ulconv, ullconv, check_buffer, exact_buffer_size - 1, num, denom) >= 0 || do_conv(ulconv, ullconv, check_buffer, 1, num, denom) >= 0 || do_conv(ulconv, ullconv, check_buffer, 0, num, denom) >= 0) { fprintf(stderr, "Can't handle buffers of insufficient size.\n"); abort(); } } static void test(opng_ullong_t num, opng_ullong_t denom, const char *expected_factor_string, const char *expected_percent_string) { char buffer_factor[BUFFER_SIZE], buffer_percent[BUFFER_SIZE]; int success; success = 1; test_conv(opng_ulratio_to_factor_string, opng_ullratio_to_factor_string, buffer_factor, BUFFER_SIZE, num, denom); if (strcmp(buffer_factor, expected_factor_string) != 0) success = 0; test_conv(opng_ulratio_to_percent_string, opng_ullratio_to_percent_string, buffer_percent, BUFFER_SIZE, num, denom); if (strcmp(buffer_percent, expected_percent_string) != 0) success = 0; ++num_tests; if (success) { printf("Passed: " "%" OPNG_LLONG_FORMAT_PREFIX "u / " "%" OPNG_LLONG_FORMAT_PREFIX "u\n", num, denom); } else { ++num_errors; printf("FAILED: " "%" OPNG_LLONG_FORMAT_PREFIX "u / " "%" OPNG_LLONG_FORMAT_PREFIX "u, " "result: (%s %s), expected: (%s %s)\n", num, denom, buffer_factor, buffer_percent, expected_factor_string, expected_percent_string); } } static void run_tests() { /* * (1) num/denom == 0/0 */ test(0, 0, "??%", "??%"); /* * (2) num/denom == INFINITY */ test( 1, 0, "INFINITY%", "INFINITY%"); test( 9, 0, "INFINITY%", "INFINITY%"); test(U32_MAX, 0, "INFINITY%", "INFINITY%"); test(ULL_MAX, 0, "INFINITY%", "INFINITY%"); /* * (3) 0 <= num/denom < 99.995% ==> precision = 0.0001 */ test( 0, 1, "0.00%", "0.00%"); /* = 0% */ test( 0, U32_MAX, "0.00%", "0.00%"); /* = 0% */ test( 0, ULL_MAX, "0.00%", "0.00%"); /* = 0% */ test( 1, U32_MAX, "0.00%", "0.00%"); /* > 0% */ test( 1, ULL_MAX, "0.00%", "0.00%"); /* > 0% */ test( 1, 20001, "0.00%", "0.00%"); /* < 0.005% */ test( 1, 20000, "0.01%", "0.01%"); /* = 0.005% */ test( 1, 19999, "0.01%", "0.01%"); /* > 0.005% */ test( 1, 10000, "0.01%", "0.01%"); /* = 0.01% */ test( 1, 4001, "0.02%", "0.02%"); /* < 0.025% */ test( 1, 4000, "0.03%", "0.03%"); /* = 0.025% */ test( 1, 3999, "0.03%", "0.03%"); /* > 0.025% */ test( 199000, 995000, "20.00%", "20.00%"); /* = 20% */ test(U32_MAX/5, U32_MAX, "20.00%", "20.00%"); /* = 20% */ test(ULL_MAX/5, ULL_MAX, "20.00%", "20.00%"); /* = 20% */ test(U32_MAX/9, U32_MAX/3, "33.33%", "33.33%"); /* < 33.33...% */ test(ULL_MAX/9, ULL_MAX/3, "33.33%", "33.33%"); /* < 33.33...% */ test( 49, 99, "49.49%", "49.49%"); /* = 49.4949...% */ test( 494949, 999999, "49.49%", "49.49%"); /* = 49.4949...% */ test(U32_MAX/2, U32_MAX, "50.00%", "50.00%"); /* < 50% */ test(ULL_MAX/2, ULL_MAX, "50.00%", "50.00%"); /* < 50% */ test(U32_MAX/2, U32_MAX-1, "50.00%", "50.00%"); /* = 50% */ test(ULL_MAX/2, ULL_MAX-1, "50.00%", "50.00%"); /* = 50% */ test( 50005, 100000, "50.01%", "50.01%"); /* = 50.005% */ test( 50, 99, "50.51%", "50.51%"); /* = 50.5050...% */ test( 505050, 999999, "50.51%", "50.51%"); /* = 50.5050...% */ test( 99995, 100001, "99.99%", "99.99%"); /* < 99.95% */ /* * (4) 0.995 <= num/denom < INFINITY and force_percent * (5) 0.995 <= num/denom < 99.995 ==> precision = 0.01 */ test( 99995, 100000, "1.00x", "100%"); /* = 99.95% */ test(U32_MAX-1, U32_MAX, "1.00x", "100%"); /* < 1.0 */ test(ULL_MAX-1, ULL_MAX, "1.00x", "100%"); /* < 1.0 */ test( 1, 1, "1.00x", "100%"); /* = 1.0 */ test( U32_MAX, U32_MAX, "1.00x", "100%"); /* = 1.0 */ test( ULL_MAX, ULL_MAX, "1.00x", "100%"); /* = 1.0 */ test( U32_MAX, U32_MAX-1, "1.00x", "100%"); /* > 1.0 */ test( ULL_MAX, ULL_MAX-1, "1.00x", "100%"); /* > 1.0 */ test( 12350, 10001, "1.23x", "123%"); /* < 1.235 */ test( 12350, 10000, "1.24x", "124%"); /* = 1.235 */ test(U32_MAX, U32_MAX/2+1, "2.00x", "200%"); /* < 2.0 */ test(ULL_MAX, ULL_MAX/2+1, "2.00x", "200%"); /* < 2.0 */ test(U32_MAX-1, U32_MAX/2, "2.00x", "200%"); /* = 2.0 */ test(ULL_MAX-1, ULL_MAX/2, "2.00x", "200%"); /* = 2.0 */ test( U32_MAX, U32_MAX/2, "2.00x", "200%"); /* > 2.0 */ test( ULL_MAX, ULL_MAX/2, "2.00x", "200%"); /* > 2.0 */ test( U32_MAX, U32_MAX/6, "6.00x", "600%"); /* > 6.0 */ test( ULL_MAX, ULL_MAX/6, "6.00x", "600%"); /* > 6.0 */ test( U32_MAX, U32_MAX/9, "9.00x", "900%"); /* > 9.0 */ test( ULL_MAX, ULL_MAX/9, "9.00x", "900%"); /* > 9.0 */ test( 1299, 100, "12.99x", "1299%"); /* = 12.99 */ test( 12999, 1000, "13.00x", "1300%"); /* = 12.999 */ test(U32_MAX, U32_MAX/99, "99.00x", "9900%"); /* > 99.0 */ test(ULL_MAX, ULL_MAX/99, "99.00x", "9900%"); /* > 99.0 */ test( 999950, 10001, "99.99x", "9999%"); /* < 99.995 */ test( 999949, 10000, "99.99x", "9999%"); /* < 99.995 */ /* * (4) 0.995 <= num/denom < INFINITY and force_percent * (6) 99.5 <= num/denom < INFINITY ==> precision = 1.0 */ test( 999950, 10000, "100x", "10000%"); /* = 99.995 */ test( 502, 5, "100x", "10040%"); /* < 100.5 */ test( 1004, 10, "100x", "10040%"); /* < 100.5 */ test( 1005, 10, "101x", "10050%"); /* = 100.5 */ test( 503, 5, "101x", "10060%"); /* > 100.5 */ test( 1006, 10, "101x", "10060%"); /* > 100.5 */ test( 12399, 100, "124x", "12399%"); /* = 123.99 */ test( 123999, 1000, "124x", "12400%"); /* = 123.999 */ test(U32_MAX, U32_MAX/999, "999x", "99900%"); /* > 999.0 */ test(ULL_MAX, ULL_MAX/999, "999x", "99900%"); /* > 999.0 */ test( 999499, 1000, "999x", "99950%"); /* < 999.5 */ test( 999500, 1000, "1000x", "99950%"); /* = 999.5 */ } int main() { run_tests(); if (num_errors != 0) { printf("** %d/%d tests FAILED **\n", num_errors, num_tests); return 1; } else { printf("** %d tests passed **\n", num_tests); return 0; } } optipng-0.7.7/src/optipng/wildargs.c000066400000000000000000000021271343170417500174430ustar00rootroot00000000000000/* * wildargs.c * Automatic command-line wildcard expansion for environments that * are not based on the Un*x shell. * * Copyright (C) 2003-2017 Cosmin Truta. * * This software is distributed under the zlib license. * Please see the accompanying LICENSE file. */ /* * Dummy header inclusion for a guaranteed non-empty translation unit. */ #include /* * Automatic wildcard expansion for Microsoft Visual C++. */ #ifdef _MSC_VER #if defined _WIN32 || defined _WIN64 /* The following line is inspired from MinGW32 by Colin Peters. */ int _dowildcard = 1; #endif #endif /* * Automatic wildcard expansion for Borland C++. */ #ifdef __BORLANDC__ #if defined _WIN32 || defined __WIN32__ || defined _WIN64 || defined __WIN64__ /* The following lines are inspired from BMP2PNG by MIYASAKA Masaru. */ #include typedef void _RTLENTRY (* _RTLENTRY _argv_expand_fn)(char *, _PFN_ADDARG); typedef void _RTLENTRY (* _RTLENTRY _wargv_expand_fn)(wchar_t *, _PFN_ADDARG); _argv_expand_fn _argv_expand_ptr = _expand_wild; _wargv_expand_fn _wargv_expand_ptr = _wexpand_wild; #endif #endif optipng-0.7.7/src/pngxtern/000077500000000000000000000000001343170417500156465ustar00rootroot00000000000000optipng-0.7.7/src/pngxtern/Makefile.in000066400000000000000000000031071343170417500177140ustar00rootroot00000000000000.PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = @CC@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ LD = @LD@ LDFLAGS = @LDFLAGS@ AR = @AR@ ARFLAGS = @ARFLAGS@ RANLIB = @RANLIB@ RM_F = @RM_F@ @USE_SYSTEM_ZLIB_FALSE@ZDIR = ../zlib @USE_SYSTEM_LIBPNG_FALSE@PNGDIR = ../libpng GIFDIR = ../gifread PNMDIR = ../pnmio TIFFDIR = ../minitiff PNGXTERN_LIB = libpngxtern.a PNGXREAD_OBJS = pngxread.o pngxrbmp.o pngxrgif.o pngxrjpg.o pngxrpnm.o pngxrtif.o PNGXUTIL_OBJS = pngxio.o pngxmem.o pngxset.o PNGXTERN_OBJS = $(PNGXREAD_OBJS) $(PNGXUTIL_OBJS) @USE_SYSTEM_ZLIB_FALSE@PNGXTERN_DEPINCLUDE_ZLIB = -I$(ZDIR) @USE_SYSTEM_ZLIB_TRUE@PNGXTERN_DEPINCLUDE_ZLIB = @USE_SYSTEM_LIBPNG_FALSE@PNGXTERN_DEPINCLUDE_LIBPNG = -I$(PNGDIR) @USE_SYSTEM_LIBPNG_TRUE@PNGXTERN_DEPINCLUDE_LIBPNG = PNGXTERN_DEPINCLUDES = \ $(PNGXTERN_DEPINCLUDE_ZLIB) \ $(PNGXTERN_DEPINCLUDE_LIBPNG) \ -I$(GIFDIR) \ -I$(PNMDIR) \ -I$(TIFFDIR) all: $(PNGXTERN_LIB) test: check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PNGXTERN_DEPINCLUDES) -o $@ $< $(PNGXTERN_LIB): $(PNGXTERN_OBJS) $(AR) $(ARFLAGS) $@ $(PNGXTERN_OBJS) $(RANLIB) $@ pngxio.o: pngxio.c pngxutil.h pngxmem.o: pngxmem.c pngxutil.h pngxset.o: pngxset.c pngxutil.h pngxread.o: pngxread.c pngxtern.h pngxutil.h pngxrbmp.o: pngxrbmp.c pngxtern.h pngxutil.h pngxrgif.o: pngxrgif.c pngxtern.h pngxutil.h pngxrjpg.o: pngxrjpg.c pngxtern.h pngxutil.h pngxrpnm.o: pngxrpnm.c pngxtern.h pngxutil.h pngxrtif.o: pngxrtif.c pngxtern.h pngxutil.h clean: -$(RM_F) $(PNGXTERN_LIB) $(PNGXTERN_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/pngxtern/build/000077500000000000000000000000001343170417500167455ustar00rootroot00000000000000optipng-0.7.7/src/pngxtern/build/bcc32.mk000066400000000000000000000031671343170417500202010ustar00rootroot00000000000000# bcc32.mk # Generated from Makefile.in # Preconfigured for Borland C++ # # Usage: make -f build\bcc32.mk CC = bcc32 CFLAGS = -O2 -d -k- -w CPP = #cpp32 -P- CPPFLAGS = LD = $(CC) LDFLAGS = $(CFLAGS) AR = tlib ARFLAGS = /C RM_F = del /q ZDIR = ..\zlib PNGDIR = ..\libpng GIFDIR = ..\gifread PNMDIR = ..\pnmio TIFFDIR = ..\minitiff PNGXTERN_LIB = pngxtern.lib PNGXREAD_OBJS = pngxread.obj pngxrbmp.obj pngxrgif.obj pngxrjpg.obj pngxrpnm.obj pngxrtif.obj PNGXREAD_LIBOBJS = +pngxread.obj +pngxrbmp.obj +pngxrgif.obj +pngxrjpg.obj +pngxrpnm.obj +pngxrtif.obj PNGXUTIL_OBJS = pngxio.obj pngxmem.obj pngxset.obj PNGXUTIL_LIBOBJS = +pngxio.obj +pngxmem.obj +pngxset.obj PNGXTERN_OBJS = $(PNGXREAD_OBJS) $(PNGXUTIL_OBJS) PNGXTERN_LIBOBJS = $(PNGXREAD_LIBOBJS) $(PNGXUTIL_LIBOBJS) PNGXTERN_DEPINCLUDE_ZLIB = -I$(ZDIR) PNGXTERN_DEPINCLUDE_LIBPNG = -I$(PNGDIR) PNGXTERN_DEPINCLUDES = \ $(PNGXTERN_DEPINCLUDE_ZLIB) \ $(PNGXTERN_DEPINCLUDE_LIBPNG) \ -I$(GIFDIR) \ -I$(PNMDIR) \ -I$(TIFFDIR) all: $(PNGXTERN_LIB) test: check: test .c.obj: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PNGXTERN_DEPINCLUDES) -o$@ $< $(PNGXTERN_LIB): $(PNGXTERN_OBJS) $(AR) $(ARFLAGS) $@ $(PNGXTERN_LIBOBJS) pngxio.obj: pngxio.c pngxutil.h pngxmem.obj: pngxmem.c pngxutil.h pngxset.obj: pngxset.c pngxutil.h pngxread.obj: pngxread.c pngxtern.h pngxutil.h pngxrbmp.obj: pngxrbmp.c pngxtern.h pngxutil.h pngxrgif.obj: pngxrgif.c pngxtern.h pngxutil.h pngxrjpg.obj: pngxrjpg.c pngxtern.h pngxutil.h pngxrpnm.obj: pngxrpnm.c pngxtern.h pngxutil.h pngxrtif.obj: pngxrtif.c pngxtern.h pngxutil.h clean: -$(RM_F) $(PNGXTERN_LIB) $(PNGXTERN_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/pngxtern/build/clang.mk000066400000000000000000000030201343170417500203550ustar00rootroot00000000000000# clang.mk # Generated from Makefile.in # Preconfigured for clang # # Usage: make -f build/clang.mk .PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = clang CFLAGS = -O2 -Wall -Wextra CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s AR = ar ARFLAGS = cru RANLIB = ranlib RM_F = rm -f ZDIR = ../zlib PNGDIR = ../libpng GIFDIR = ../gifread PNMDIR = ../pnmio TIFFDIR = ../minitiff PNGXTERN_LIB = libpngxtern.a PNGXREAD_OBJS = pngxread.o pngxrbmp.o pngxrgif.o pngxrjpg.o pngxrpnm.o pngxrtif.o PNGXUTIL_OBJS = pngxio.o pngxmem.o pngxset.o PNGXTERN_OBJS = $(PNGXREAD_OBJS) $(PNGXUTIL_OBJS) PNGXTERN_DEPINCLUDE_ZLIB = -I$(ZDIR) #PNGXTERN_DEPINCLUDE_ZLIB = PNGXTERN_DEPINCLUDE_LIBPNG = -I$(PNGDIR) #PNGXTERN_DEPINCLUDE_LIBPNG = PNGXTERN_DEPINCLUDES = \ $(PNGXTERN_DEPINCLUDE_ZLIB) \ $(PNGXTERN_DEPINCLUDE_LIBPNG) \ -I$(GIFDIR) \ -I$(PNMDIR) \ -I$(TIFFDIR) all: $(PNGXTERN_LIB) test: check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PNGXTERN_DEPINCLUDES) -o $@ $< $(PNGXTERN_LIB): $(PNGXTERN_OBJS) $(AR) $(ARFLAGS) $@ $(PNGXTERN_OBJS) $(RANLIB) $@ pngxio.o: pngxio.c pngxutil.h pngxmem.o: pngxmem.c pngxutil.h pngxset.o: pngxset.c pngxutil.h pngxread.o: pngxread.c pngxtern.h pngxutil.h pngxrbmp.o: pngxrbmp.c pngxtern.h pngxutil.h pngxrgif.o: pngxrgif.c pngxtern.h pngxutil.h pngxrjpg.o: pngxrjpg.c pngxtern.h pngxutil.h pngxrpnm.o: pngxrpnm.c pngxtern.h pngxutil.h pngxrtif.o: pngxrtif.c pngxtern.h pngxutil.h clean: -$(RM_F) $(PNGXTERN_LIB) $(PNGXTERN_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/pngxtern/build/gcc.mk000066400000000000000000000030101343170417500200240ustar00rootroot00000000000000# gcc.mk # Generated from Makefile.in # Preconfigured for gcc # # Usage: make -f build/gcc.mk .PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = gcc CFLAGS = -O2 -Wall -Wextra CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s AR = ar ARFLAGS = cru RANLIB = ranlib RM_F = rm -f ZDIR = ../zlib PNGDIR = ../libpng GIFDIR = ../gifread PNMDIR = ../pnmio TIFFDIR = ../minitiff PNGXTERN_LIB = libpngxtern.a PNGXREAD_OBJS = pngxread.o pngxrbmp.o pngxrgif.o pngxrjpg.o pngxrpnm.o pngxrtif.o PNGXUTIL_OBJS = pngxio.o pngxmem.o pngxset.o PNGXTERN_OBJS = $(PNGXREAD_OBJS) $(PNGXUTIL_OBJS) PNGXTERN_DEPINCLUDE_ZLIB = -I$(ZDIR) #PNGXTERN_DEPINCLUDE_ZLIB = PNGXTERN_DEPINCLUDE_LIBPNG = -I$(PNGDIR) #PNGXTERN_DEPINCLUDE_LIBPNG = PNGXTERN_DEPINCLUDES = \ $(PNGXTERN_DEPINCLUDE_ZLIB) \ $(PNGXTERN_DEPINCLUDE_LIBPNG) \ -I$(GIFDIR) \ -I$(PNMDIR) \ -I$(TIFFDIR) all: $(PNGXTERN_LIB) test: check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PNGXTERN_DEPINCLUDES) -o $@ $< $(PNGXTERN_LIB): $(PNGXTERN_OBJS) $(AR) $(ARFLAGS) $@ $(PNGXTERN_OBJS) $(RANLIB) $@ pngxio.o: pngxio.c pngxutil.h pngxmem.o: pngxmem.c pngxutil.h pngxset.o: pngxset.c pngxutil.h pngxread.o: pngxread.c pngxtern.h pngxutil.h pngxrbmp.o: pngxrbmp.c pngxtern.h pngxutil.h pngxrgif.o: pngxrgif.c pngxtern.h pngxutil.h pngxrjpg.o: pngxrjpg.c pngxtern.h pngxutil.h pngxrpnm.o: pngxrpnm.c pngxtern.h pngxutil.h pngxrtif.o: pngxrtif.c pngxtern.h pngxutil.h clean: -$(RM_F) $(PNGXTERN_LIB) $(PNGXTERN_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/pngxtern/build/unix.mk000066400000000000000000000030051343170417500202570ustar00rootroot00000000000000# unix.mk # Generated from Makefile.in # Preconfigured for Unix (generic) # # Usage: make -f build/unix.mk .PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = cc CFLAGS = -O CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s AR = ar ARFLAGS = cru RANLIB = ranlib RM_F = rm -f ZDIR = ../zlib PNGDIR = ../libpng GIFDIR = ../gifread PNMDIR = ../pnmio TIFFDIR = ../minitiff PNGXTERN_LIB = libpngxtern.a PNGXREAD_OBJS = pngxread.o pngxrbmp.o pngxrgif.o pngxrjpg.o pngxrpnm.o pngxrtif.o PNGXUTIL_OBJS = pngxio.o pngxmem.o pngxset.o PNGXTERN_OBJS = $(PNGXREAD_OBJS) $(PNGXUTIL_OBJS) PNGXTERN_DEPINCLUDE_ZLIB = -I$(ZDIR) #PNGXTERN_DEPINCLUDE_ZLIB = PNGXTERN_DEPINCLUDE_LIBPNG = -I$(PNGDIR) #PNGXTERN_DEPINCLUDE_LIBPNG = PNGXTERN_DEPINCLUDES = \ $(PNGXTERN_DEPINCLUDE_ZLIB) \ $(PNGXTERN_DEPINCLUDE_LIBPNG) \ -I$(GIFDIR) \ -I$(PNMDIR) \ -I$(TIFFDIR) all: $(PNGXTERN_LIB) test: check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PNGXTERN_DEPINCLUDES) -o $@ $< $(PNGXTERN_LIB): $(PNGXTERN_OBJS) $(AR) $(ARFLAGS) $@ $(PNGXTERN_OBJS) $(RANLIB) $@ pngxio.o: pngxio.c pngxutil.h pngxmem.o: pngxmem.c pngxutil.h pngxset.o: pngxset.c pngxutil.h pngxread.o: pngxread.c pngxtern.h pngxutil.h pngxrbmp.o: pngxrbmp.c pngxtern.h pngxutil.h pngxrgif.o: pngxrgif.c pngxtern.h pngxutil.h pngxrjpg.o: pngxrjpg.c pngxtern.h pngxutil.h pngxrpnm.o: pngxrpnm.c pngxtern.h pngxutil.h pngxrtif.o: pngxrtif.c pngxtern.h pngxutil.h clean: -$(RM_F) $(PNGXTERN_LIB) $(PNGXTERN_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/pngxtern/build/visualc.mk000066400000000000000000000027531343170417500207530ustar00rootroot00000000000000# visualc.mk # Generated from Makefile.in # Preconfigured for Microsoft Visual C++ # # Usage: nmake -f build\visualc.mk CC = cl -nologo CFLAGS = -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -MD -O2 -W4 CPP = cl -nologo -E CPPFLAGS = LD = link -nologo LDFLAGS = AR = lib -nologo ARFLAGS = RM_F = del /q ZDIR = ..\zlib PNGDIR = ..\libpng GIFDIR = ..\gifread PNMDIR = ..\pnmio TIFFDIR = ..\minitiff PNGXTERN_LIB = pngxtern.lib PNGXREAD_OBJS = pngxread.obj pngxrbmp.obj pngxrgif.obj pngxrjpg.obj pngxrpnm.obj pngxrtif.obj PNGXUTIL_OBJS = pngxio.obj pngxmem.obj pngxset.obj PNGXTERN_OBJS = $(PNGXREAD_OBJS) $(PNGXUTIL_OBJS) PNGXTERN_DEPINCLUDE_ZLIB = -I$(ZDIR) PNGXTERN_DEPINCLUDE_LIBPNG = -I$(PNGDIR) PNGXTERN_DEPINCLUDES = \ $(PNGXTERN_DEPINCLUDE_ZLIB) \ $(PNGXTERN_DEPINCLUDE_LIBPNG) \ -I$(GIFDIR) \ -I$(PNMDIR) \ -I$(TIFFDIR) all: $(PNGXTERN_LIB) test: check: test .c.obj: $(CC) -c $(CPPFLAGS) $(CFLAGS) $(PNGXTERN_DEPINCLUDES) -Fo$@ $< $(PNGXTERN_LIB): $(PNGXTERN_OBJS) $(AR) $(ARFLAGS) -out:$@ $(PNGXTERN_OBJS) pngxio.obj: pngxio.c pngxutil.h pngxmem.obj: pngxmem.c pngxutil.h pngxset.obj: pngxset.c pngxutil.h pngxread.obj: pngxread.c pngxtern.h pngxutil.h pngxrbmp.obj: pngxrbmp.c pngxtern.h pngxutil.h pngxrgif.obj: pngxrgif.c pngxtern.h pngxutil.h pngxrjpg.obj: pngxrjpg.c pngxtern.h pngxutil.h pngxrpnm.obj: pngxrpnm.c pngxtern.h pngxutil.h pngxrtif.obj: pngxrtif.c pngxtern.h pngxutil.h clean: -$(RM_F) $(PNGXTERN_LIB) $(PNGXTERN_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/pngxtern/pngxio.c000066400000000000000000000150321343170417500173170ustar00rootroot00000000000000/* * pngxio.c - libpng extension: I/O state query. * * Copyright (C) 2003-2017 Cosmin Truta. * This software is distributed under the same licensing and warranty terms * as libpng. * * NOTE: * The functionality provided in this module has "graduated", and is now * part of libpng. The original code, retrofitted as a back-port, has * limitations: it is thread-unsafe, and it only allows one png_ptr object * for reading and one for writing. * * CAUTION: * libpng-1.4.5 is the earliest version whose I/O state implementation * can be used reliably. */ #include "pngxutil.h" #define PNGX_INTERNAL #include "pngxpriv.h" #if PNG_LIBPNG_VER < 10405 static png_structp _pngxio_read_ptr; static png_structp _pngxio_write_ptr; static png_rw_ptr _pngxio_read_fn; static png_rw_ptr _pngxio_write_fn; static int _pngxio_read_io_state; static int _pngxio_write_io_state; static png_byte _pngxio_read_crt_chunk_hdr[9]; static png_byte _pngxio_write_crt_chunk_hdr[9]; static unsigned int _pngxio_read_crt_chunk_hdr_len; static unsigned int _pngxio_write_crt_chunk_hdr_len; static png_uint_32 _pngxio_read_crt_len; static png_uint_32 _pngxio_write_crt_len; static const char *_pngxio_errmsg_invalid_argument = "[PNGXIO internal] invalid argument"; /* Update io_state and call the user-supplied read/write functions. */ void /* PRIVATE */ pngxio_read_write(png_structp png_ptr, png_bytep data, size_t length) { png_rw_ptr io_data_fn; int *io_state_ptr; int io_state_op; png_byte *crt_chunk_hdr; unsigned int *crt_chunk_hdr_len_ptr; png_uint_32 *crt_len_ptr; if (png_ptr == _pngxio_read_ptr) { io_data_fn = _pngxio_read_fn; io_state_ptr = &_pngxio_read_io_state; io_state_op = PNGX_IO_READING; crt_chunk_hdr = _pngxio_read_crt_chunk_hdr; crt_chunk_hdr_len_ptr = &_pngxio_read_crt_chunk_hdr_len; crt_len_ptr = &_pngxio_read_crt_len; } else if (png_ptr == _pngxio_write_ptr) { io_data_fn = _pngxio_write_fn; io_state_ptr = &_pngxio_write_io_state; io_state_op = PNGX_IO_WRITING; crt_chunk_hdr = _pngxio_write_crt_chunk_hdr; crt_chunk_hdr_len_ptr = &_pngxio_write_crt_chunk_hdr_len; crt_len_ptr = &_pngxio_write_crt_len; } else { png_error(png_ptr, _pngxio_errmsg_invalid_argument); /* NOTREACHED */ return; } switch (*io_state_ptr & PNGX_IO_MASK_LOC) { case PNGX_IO_SIGNATURE: /* libpng must serialize the signature in a single I/O session. */ PNGX_ASSERT(length <= 8); io_data_fn(png_ptr, data, length); *io_state_ptr = io_state_op | PNGX_IO_CHUNK_HDR; *crt_chunk_hdr_len_ptr = 0; return; case PNGX_IO_CHUNK_HDR: /* libpng must serialize the chunk header in a single I/O session. * (This was done in libpng-1.2.30, but regressed in libpng-1.4.0, * so we cannot rely on it here.) */ PNGX_ASSERT(length == 4 || length == 8); PNGX_ASSERT(length + *crt_chunk_hdr_len_ptr <= 8); if (io_state_op == PNGX_IO_READING) { if (*crt_chunk_hdr_len_ptr == 0) io_data_fn(png_ptr, crt_chunk_hdr, 8); memcpy(data, crt_chunk_hdr + *crt_chunk_hdr_len_ptr, length); *crt_chunk_hdr_len_ptr += length; if (*crt_chunk_hdr_len_ptr < 8) return; *crt_len_ptr = png_get_uint_32(crt_chunk_hdr); /* memcpy(png_ptr->chunk_name, crt_chunk_hdr + 4, 4); */ } else /* io_state_op == PNGX_IO_WRITING */ { memcpy(crt_chunk_hdr + *crt_chunk_hdr_len_ptr, data, length); *crt_chunk_hdr_len_ptr += length; if (*crt_chunk_hdr_len_ptr < 8) return; *crt_len_ptr = png_get_uint_32(crt_chunk_hdr); /* memcpy(png_ptr->chunk_name, crt_chunk_hdr + 4, 4); */ io_data_fn(png_ptr, crt_chunk_hdr, 8); } *crt_chunk_hdr_len_ptr = 0; *io_state_ptr = io_state_op | PNGX_IO_CHUNK_DATA; return; case PNGX_IO_CHUNK_DATA: /* libpng may serialize the chunk data in multiple I/O sessions. */ if (length == 0) return; if (*crt_len_ptr > 0) { PNGX_ASSERT(length <= *crt_len_ptr); io_data_fn(png_ptr, data, length); *crt_len_ptr -= length; return; } *io_state_ptr = io_state_op | PNGX_IO_CHUNK_CRC; /* FALLTHROUGH */ case PNGX_IO_CHUNK_CRC: /* libpng must serialize the chunk CRC in a single I/O session. */ PNGX_ASSERT(length == 4); io_data_fn(png_ptr, data, 4); *io_state_ptr = io_state_op | PNGX_IO_CHUNK_HDR; return; } } /* Get png_ptr->io_state. */ png_uint_32 PNGAPI pngx_get_io_state(png_structp png_ptr) { png_uint_32 io_state; if (png_ptr == _pngxio_read_ptr) io_state = _pngxio_read_io_state; else if (png_ptr == _pngxio_write_ptr) io_state = _pngxio_write_io_state; else { png_error(png_ptr, _pngxio_errmsg_invalid_argument); /* NOTREACHED */ io_state = PNGX_IO_NONE; } return io_state; } /* Get png_ptr->chunk_name. */ png_bytep PNGAPI pngx_get_io_chunk_name(png_structp png_ptr) { png_bytep chunk_name; if (png_ptr == _pngxio_read_ptr) chunk_name = _pngxio_read_crt_chunk_hdr + 4; else if (png_ptr == _pngxio_write_ptr) chunk_name = _pngxio_write_crt_chunk_hdr + 4; else { png_error(png_ptr, _pngxio_errmsg_invalid_argument); /* NOTREACHED */ chunk_name = NULL; } return chunk_name; } /* Wrap png_set_read_fn. */ void PNGAPI pngx_set_read_fn(png_structp png_ptr, png_voidp io_ptr, png_rw_ptr read_data_fn) { _pngxio_read_ptr = png_ptr; _pngxio_write_ptr = NULL; _pngxio_read_fn = read_data_fn; png_set_read_fn(png_ptr, io_ptr, pngxio_read_write); _pngxio_read_io_state = PNGX_IO_READING | PNGX_IO_SIGNATURE; } /* Wrap png_set_write_fn. */ void PNGAPI pngx_set_write_fn(png_structp png_ptr, png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn) { _pngxio_write_ptr = png_ptr; _pngxio_read_ptr = NULL; _pngxio_write_fn = write_data_fn; png_set_write_fn(png_ptr, io_ptr, pngxio_read_write, output_flush_fn); _pngxio_write_io_state = PNGX_IO_WRITING | PNGX_IO_SIGNATURE; } /* Wrap png_write_sig. */ void PNGAPI pngx_write_sig(png_structp png_ptr) { #if PNG_LIBPNG_VER >= 10400 png_write_sig(png_ptr); #else /* png_write_sig is not exported from the earlier libpng versions. */ static png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; pngxio_read_write(png_ptr, png_signature, 8); /* TODO: Take png_ptr->sig_bytes into account. */ #endif } #endif /* PNG_LIBPNG_VER < 10405 */ optipng-0.7.7/src/pngxtern/pngxmem.c000066400000000000000000000043171343170417500174720ustar00rootroot00000000000000/* * pngxmem.c - libpng extension: memory allocation utilities. * * Copyright (C) 2003-2017 Cosmin Truta. * This software is distributed under the same licensing and warranty terms * as libpng. */ #include "pngxutil.h" #include #ifdef PNG_INFO_IMAGE_SUPPORTED png_bytepp PNGAPI pngx_malloc_rows(png_structp png_ptr, png_infop info_ptr, int filler) { return pngx_malloc_rows_extended(png_ptr, info_ptr, 0, filler); } png_bytepp PNGAPI pngx_malloc_rows_extended(png_structp png_ptr, png_infop info_ptr, pngx_alloc_size_t min_row_size, int filler) { pngx_alloc_size_t row_size; png_bytep row; png_bytepp rows; png_uint_32 height, i; /* Check the image dimensions and calculate the row size. */ height = png_get_image_height(png_ptr, info_ptr); if (height == 0) png_error(png_ptr, "Missing IHDR"); row_size = png_get_rowbytes(png_ptr, info_ptr); /* libpng sets row_size to 0 when the width is too large to process. */ if (row_size == 0 || (pngx_alloc_size_t)height > (pngx_alloc_size_t)(-1) / sizeof(png_bytep)) png_error(png_ptr, "Can't handle exceedingly large image dimensions"); if (row_size < min_row_size) row_size = min_row_size; /* Deallocate the currently-existing rows. */ png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); /* Allocate memory for the row index. */ rows = (png_bytepp)png_malloc(png_ptr, (pngx_alloc_size_t)(height * sizeof(png_bytep))); if (rows == NULL) return NULL; /* Allocate memory for each row. */ for (i = 0; i < height; ++i) { row = (png_bytep)png_malloc(png_ptr, row_size); if (row == NULL) { /* Release the memory allocated up to the point of failure. */ while (i > 0) png_free(png_ptr, rows[--i]); png_free(png_ptr, rows); return NULL; } if (filler >= 0) memset(row, filler, row_size); rows[i] = row; } /* Set the row pointers. */ png_set_rows(png_ptr, info_ptr, rows); return rows; } #if 0 /* not necessary */ void PNGAPI pngx_free_rows(png_structp png_ptr, png_infop info_ptr) { png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); } #endif #endif /* PNG_INFO_IMAGE_SUPPORTED */ optipng-0.7.7/src/pngxtern/pngxpriv.h000066400000000000000000000036341343170417500177020ustar00rootroot00000000000000/* * pngxpriv.h - private helpers for pngxtern. * * Copyright (C) 2003-2011 Cosmin Truta. * This software is distributed under the same licensing and warranty terms * as libpng. */ #ifndef PNGXPRIV_H #define PNGXPRIV_H /* This header is not meant to be used outside pngxtern. */ #ifdef PNGX_INTERNAL #include "png.h" #include #if defined(PNGX_DEBUG) && (PNGX_DEBUG > 0) #include #define PNGX_ASSERT(cond) assert(cond) #else #define PNGX_ASSERT(cond) ((void)0) #endif #ifdef __cplusplus extern "C" { #endif /* BMP support */ int pngx_sig_is_bmp(png_bytep sig, size_t sig_size, png_const_charpp fmt_name_ptr, png_const_charpp fmt_long_name_ptr); int pngx_read_bmp(png_structp png_ptr, png_infop info_ptr, FILE *stream); /* GIF support */ int pngx_sig_is_gif(png_bytep sig, size_t sig_size, png_const_charpp fmt_name_ptr, png_const_charpp fmt_long_name_ptr); int pngx_read_gif(png_structp png_ptr, png_infop info_ptr, FILE *stream); /* JPEG support (well, not really...) */ int pngx_sig_is_jpeg(png_bytep sig, size_t sig_size, png_const_charpp fmt_name_ptr, png_const_charpp fmt_long_name_ptr); int pngx_read_jpeg(png_structp png_ptr, png_infop info_ptr, FILE *stream); /* PNM support */ int pngx_sig_is_pnm(png_bytep sig, size_t sig_size, png_const_charpp fmt_name_ptr, png_const_charpp fmt_long_name_ptr); int pngx_read_pnm(png_structp png_ptr, png_infop info_ptr, FILE *stream); /* TIFF support (partial) */ int pngx_sig_is_tiff(png_bytep sig, size_t sig_size, png_const_charpp fmt_name_ptr, png_const_charpp fmt_long_name_ptr); int pngx_read_tiff(png_structp png_ptr, png_infop info_ptr, FILE *stream); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* PNGX_INTERNAL */ #endif /* PNGXPRIV_H */ optipng-0.7.7/src/pngxtern/pngxrbmp.c000066400000000000000000000574161343170417500176640ustar00rootroot00000000000000/* * pngxrbmp.c - libpng external I/O: BMP reader. * Copyright (C) 2003-2016 Cosmin Truta and the Contributing Authors. * * This code was derived from "bmp2png.c" by MIYASAKA Masaru, and * is distributed under the same copyright and warranty terms as libpng. */ #include "pngxtern.h" #include "pngxutil.h" #include #include #define PNGX_INTERNAL #include "pngxpriv.h" /*****************************************************************************/ /* BMP file header macros */ /*****************************************************************************/ /* BMP file signature */ #define BMP_SIGNATURE 0x4d42 /* "BM" */ #define BMP_SIG_BYTES 2 /* BITMAPFILEHEADER */ #define BFH_WTYPE 0 /* WORD bfType; */ #define BFH_DSIZE 2 /* DWORD bfSize; */ #define BFH_WRESERVED1 6 /* WORD bfReserved1; */ #define BFH_WRESERVED2 8 /* WORD bfReserved2; */ #define BFH_DOFFBITS 10 /* DWORD bfOffBits; */ #define BFH_DBIHSIZE 14 /* DWORD biSize; */ #define FILEHED_SIZE 14 /* sizeof(BITMAPFILEHEADER) */ #define BIHSIZE_SIZE 4 /* sizeof(biSize) */ /* BITMAPINFOHEADER */ #define BIH_DSIZE 0 /* DWORD biSize; */ #define BIH_LWIDTH 4 /* LONG biWidth; */ #define BIH_LHEIGHT 8 /* LONG biHeight; */ #define BIH_WPLANES 12 /* WORD biPlanes; */ #define BIH_WBITCOUNT 14 /* WORD biBitCount; */ #define BIH_DCOMPRESSION 16 /* DWORD biCompression; */ #define BIH_DSIZEIMAGE 20 /* DWORD biSizeImage; */ #define BIH_LXPELSPERMETER 24 /* LONG biXPelsPerMeter; */ #define BIH_LYPELSPERMETER 28 /* LONG biYPelsPerMeter; */ #define BIH_DCLRUSED 32 /* DWORD biClrUsed; */ #define BIH_DCLRIMPORTANT 36 /* DWORD biClrImportant; */ #define B4H_DREDMASK 40 /* DWORD bV4RedMask; */ #define B4H_DGREENMASK 44 /* DWORD bV4GreenMask; */ #define B4H_DBLUEMASK 48 /* DWORD bV4BlueMask; */ #define B4H_DALPHAMASK 52 /* DWORD bV4AlphaMask; */ #define B4H_DCSTYPE 56 /* DWORD bV4CSType; */ #define B4H_XENDPOINTS 60 /* CIEXYZTRIPLE bV4Endpoints; */ #define B4H_DGAMMARED 96 /* DWORD bV4GammaRed; */ #define B4H_DGAMMAGREEN 100 /* DWORD bV4GammaGreen; */ #define B4H_DGAMMABLUE 104 /* DWORD bV4GammaBlue; */ #define B5H_DINTENT 108 /* DWORD bV5Intent; */ #define B5H_DPROFILEDATA 112 /* DWORD bV5ProfileData; */ #define B5H_DPROFILESIZE 116 /* DWORD bV5ProfileSize; */ #define B5H_DRESERVED 120 /* DWORD bV5Reserved; */ #define INFOHED_SIZE 40 /* sizeof(BITMAPINFOHEADER) */ #define BMPV4HED_SIZE 108 /* sizeof(BITMAPV4HEADER) */ #define BMPV5HED_SIZE 124 /* sizeof(BITMAPV5HEADER) */ /* BITMAPCOREHEADER */ #define BCH_DSIZE 0 /* DWORD bcSize; */ #define BCH_WWIDTH 4 /* WORD bcWidth; */ #define BCH_WHEIGHT 6 /* WORD bcHeight; */ #define BCH_WPLANES 8 /* WORD bcPlanes; */ #define BCH_WBITCOUNT 10 /* WORD bcBitCount; */ #define COREHED_SIZE 12 /* sizeof(BITMAPCOREHEADER) */ /* RGB */ #define RGB_BLUE 0 /* BYTE rgbBlue; */ #define RGB_GREEN 1 /* BYTE rgbGreen; */ #define RGB_RED 2 /* BYTE rgbRed; */ #define RGB_RESERVED 3 /* BYTE rgbReserved; */ #define RGBTRIPLE_SIZE 3 /* sizeof(RGBTRIPLE) */ #define RGBQUAD_SIZE 4 /* sizeof(RGBQUAD) */ /* Constants for the biCompression field */ #ifndef BI_RGB #define BI_RGB 0 /* Uncompressed format */ #define BI_RLE8 1 /* RLE format (8 bits/pixel) */ #define BI_RLE4 2 /* RLE format (4 bits/pixel) */ #define BI_BITFIELDS 3 /* Bitfield format */ #define BI_JPEG 4 /* JPEG format */ #define BI_PNG 5 /* PNG format */ #endif /*****************************************************************************/ /* BMP memory utilities */ /*****************************************************************************/ static unsigned int bmp_get_word(png_bytep ptr) { return (unsigned int)ptr[0] + ((unsigned int)ptr[1] << 8); } static png_uint_32 bmp_get_dword(png_bytep ptr) { return ((png_uint_32)ptr[0]) + ((png_uint_32)ptr[1] << 8) + ((png_uint_32)ptr[2] << 16) + ((png_uint_32)ptr[3] << 24); } /*****************************************************************************/ /* BMP helpers */ /*****************************************************************************/ static void bmp_memset_bytes(png_bytep ptr, size_t offset, int ch, size_t len) { memset(ptr + offset, ch, len); } static void bmp_memset_halfbytes(png_bytep ptr, size_t offset, int ch, size_t len) { if (len == 0) return; ptr += offset / 2; if (offset & 1) /* use half-byte operations at odd offset */ { *ptr = (png_byte)((*ptr & 0xf0) | (ch & 0x0f)); ch = ((ch & 0xf0) >> 4) | ((ch & 0x0f) << 4); ++ptr; --len; } memset(ptr, ch, len / 2); if (len & 1) ptr[len / 2] = (png_byte)(ch & 0xf0); } static size_t bmp_fread_bytes(png_bytep ptr, size_t offset, size_t len, FILE *stream) { size_t result; result = fread(ptr + offset, 1, len, stream); if (len & 1) getc(stream); /* skip padding */ return result; } static size_t bmp_fread_halfbytes(png_bytep ptr, size_t offset, size_t len, FILE *stream) { size_t result; int ch; if (len == 0) return 0; ptr += offset / 2; if (offset & 1) /* use half-byte operations at odd offset */ { for (result = 0; result < len - 1; result += 2) { ch = getc(stream); if (ch == EOF) break; *ptr = (png_byte)((*ptr & 0xf0) | ((ch & 0xf0) >> 4)); ++ptr; *ptr = (png_byte)((ch & 0x0f) << 4); } } else { result = fread(ptr, 1, (len + 1) / 2, stream) * 2; } if (len & 2) getc(stream); /* skip padding */ return (result <= len) ? result : len; } /*****************************************************************************/ /* BMP packbit (BITFIELDS) helpers */ /*****************************************************************************/ static void bmp_process_mask(png_uint_32 bmp_mask, png_bytep sig_bit, png_bytep shift_bit) { *sig_bit = *shift_bit = (png_byte)0; if (bmp_mask == 0) return; while ((bmp_mask & 1) == 0) { bmp_mask >>= 1; ++*shift_bit; } while (bmp_mask != 0) { if ((bmp_mask & 1) == 0 || *sig_bit >= 8) { *sig_bit = (png_byte)0; return; } bmp_mask >>= 1; ++*sig_bit; } } /*****************************************************************************/ /* BMP I/O utilities */ /*****************************************************************************/ static size_t bmp_read_rows(png_bytepp begin_row, png_bytepp end_row, size_t row_size, unsigned int compression, FILE *stream) { size_t result; png_bytepp crt_row; int inc; size_t crtn, dcrtn, endn; unsigned int len, b1, b2; int ch; void (*bmp_memset_fn)(png_bytep, size_t, int, size_t); size_t (*bmp_fread_fn)(png_bytep, size_t, size_t, FILE *); if (row_size == 0) return 0; /* this should not happen */ inc = (begin_row <= end_row) ? 1 : -1; crtn = 0; result = 0; if (compression == BI_RLE4) { endn = row_size * 2; if (endn <= row_size) return 0; /* overflow */ bmp_memset_fn = bmp_memset_halfbytes; bmp_fread_fn = bmp_fread_halfbytes; } else { endn = row_size; bmp_memset_fn = bmp_memset_bytes; bmp_fread_fn = bmp_fread_bytes; } if (compression == BI_RGB || compression == BI_BITFIELDS) { /* Read uncompressed bitmap. */ for (crt_row = begin_row; crt_row != end_row; crt_row += inc) { crtn = bmp_fread_fn(*crt_row, 0, endn, stream); if (crtn != endn) break; ++result; } } else if (compression == BI_RLE8 || compression == BI_RLE4) { /* Read RLE-compressed bitmap. */ if (compression == BI_RLE8) { endn = row_size; } else /* BI_RLE4 */ { endn = row_size * 2; if (endn <= row_size) return 0; /* overflow */ } for (crt_row = begin_row; crt_row != end_row; ) { ch = getc(stream); b1 = (unsigned int)ch; ch = getc(stream); b2 = (unsigned int)ch; if (ch == EOF) break; if (b1 == 0) /* escape */ { if (b2 == 0) /* end of line */ { bmp_memset_fn(*crt_row, crtn, 0, endn - crtn); crt_row += inc; crtn = 0; ++result; if (crt_row == end_row) /* all rows are read */ { ch = getc(stream); /* check for the end of bitmap */ if (ch != EOF && ch != 0) { ungetc(ch, stream); /* forget about the end of bitmap */ break; } getc(stream); /* expect 1, but break the loop anyway */ break; } } else if (b2 == 1) /* end of bitmap */ { bmp_memset_fn(*crt_row, crtn, 0, endn - crtn); crt_row += inc; crtn = 0; result = (begin_row <= end_row) ? (end_row - begin_row) : (begin_row - end_row); break; /* the rest is wiped out at the end */ } else if (b2 == 2) /* delta */ { ch = getc(stream); b1 = (unsigned int)ch; /* horiz. offset */ ch = getc(stream); b2 = (unsigned int)ch; /* vert. offset */ if (ch == EOF) break; dcrtn = (b1 < endn - crtn) ? (crtn + b1) : endn; for ( ; b2 > 0; --b2) { bmp_memset_fn(*crt_row, crtn, 0, endn - crtn); crt_row += inc; crtn = 0; ++result; if (crt_row == end_row) break; } if (crt_row != end_row) bmp_memset_fn(*crt_row, crtn, 0, dcrtn - crtn); } else /* b2 >= 3 bytes in absolute mode */ { len = (b2 <= endn - crtn) ? b2 : (unsigned int)(endn - crtn); if (bmp_fread_fn(*crt_row, crtn, len, stream) != len) break; crtn += len; } } else /* b1 > 0 bytes in run-length encoded mode */ { len = (b1 <= endn - crtn) ? b1 : (unsigned int)(endn - crtn); bmp_memset_fn(*crt_row, crtn, (int)b2, len); crtn += len; } } } else return 0; /* error: compression method not applicable. */ /* Wipe out the portion left unread. */ for ( ; crt_row != end_row; crt_row += inc) { bmp_memset_fn(*crt_row, crtn, 0, endn - crtn); crtn = 0; } return result; } /*****************************************************************************/ /* BMP-to-PNG sample conversion */ /*****************************************************************************/ static void bmp_to_png_rows(png_bytepp row_pointers, png_uint_32 width, png_uint_32 height, unsigned int pixdepth, png_bytep rgba_sig, png_bytep rgba_shift) { png_bytep src_ptr, dest_ptr; unsigned int rgba_mask[4]; unsigned int num_samples, sample, mask; unsigned int wpix; png_uint_32 dwpix; png_uint_32 x, y; unsigned int i; if (pixdepth == 24) /* BGR -> RGB */ { for (y = 0; y < height; ++y) { src_ptr = row_pointers[y]; for (x = 0; x < width; ++x, src_ptr += 3) { png_byte tmp = src_ptr[0]; src_ptr[0] = src_ptr[2]; src_ptr[2] = tmp; } } return; } num_samples = (rgba_sig[3] != 0) ? 4 : 3; for (i = 0; i < num_samples; ++i) rgba_mask[i] = (1U << rgba_sig[i]) - 1; if (pixdepth == 16) { for (y = 0; y < height; ++y) { src_ptr = row_pointers[y] + (width - 1) * 2; dest_ptr = row_pointers[y] + (width - 1) * num_samples; for (x = 0; x < width; ++x, src_ptr -= 2, dest_ptr -= num_samples) { /* Inline bmp_get_word() for performance reasons. */ wpix = (unsigned int)src_ptr[0] + ((unsigned int)src_ptr[1] << 8); for (i = 0; i < num_samples; ++i) { mask = rgba_mask[i]; sample = (wpix >> rgba_shift[i]) & mask; dest_ptr[i] = (png_byte)((sample * 255 + mask / 2) / mask); } } } } else if (pixdepth == 32) { for (y = 0; y < height; ++y) { src_ptr = dest_ptr = row_pointers[y]; for (x = 0; x < width; ++x, src_ptr += 4, dest_ptr += num_samples) { /* Inline bmp_get_dword() for performance reasons. */ dwpix = (png_uint_32)src_ptr[0] + ((png_uint_32)src_ptr[1] << 8) + ((png_uint_32)src_ptr[2] << 16) + ((png_uint_32)src_ptr[3] << 24); for (i = 0; i < num_samples; ++i) { mask = rgba_mask[i]; sample = (dwpix >> rgba_shift[i]) & mask; dest_ptr[i] = (png_byte)((sample * 255 + mask / 2) / mask); } } } } /* else do nothing */ } /*****************************************************************************/ /* BMP read support for pngxtern */ /*****************************************************************************/ int /* PRIVATE */ pngx_sig_is_bmp(png_bytep sig, size_t sig_size, png_const_charpp fmt_name_ptr, png_const_charpp fmt_long_name_ptr) { static const char bmp_fmt_name[] = "BMP"; static const char os2bmp_fmt_long_name[] = "OS/2 Bitmap"; static const char winbmp_fmt_long_name[] = "Windows Bitmap"; png_uint_32 bihsize; /* Require at least the bitmap file header and the subsequent 4 bytes. */ if (sig_size < FILEHED_SIZE + 4) return -1; /* insufficient data */ if (bmp_get_word(sig) != BMP_SIGNATURE) return 0; /* not BMP */ /* Avoid using bfhsize because it is not reliable. */ bihsize = bmp_get_dword(sig + FILEHED_SIZE); if ((bihsize > PNG_UINT_31_MAX) || (bihsize != COREHED_SIZE && bihsize < INFOHED_SIZE)) return 0; /* garbage in bihsize, this cannot be BMP */ /* Store the format name. */ if (fmt_name_ptr != NULL) *fmt_name_ptr = bmp_fmt_name; if (fmt_long_name_ptr != NULL) { if (bihsize == COREHED_SIZE) *fmt_long_name_ptr = os2bmp_fmt_long_name; else *fmt_long_name_ptr = winbmp_fmt_long_name; } return 1; /* BMP */ } int /* PRIVATE */ pngx_read_bmp(png_structp png_ptr, png_infop info_ptr, FILE *stream) { png_byte bfh[FILEHED_SIZE + BMPV5HED_SIZE]; png_bytep const bih = bfh + FILEHED_SIZE; png_byte rgbq[RGBQUAD_SIZE]; png_uint_32 offbits, bihsize, skip; png_uint_32 width, height, rowsize; int topdown; unsigned int pixdepth; png_uint_32 compression; unsigned int palsize, palnum; png_uint_32 rgba_mask[4]; png_byte rgba_sig[4], rgba_shift[4]; int bit_depth, color_type; png_color palette[256]; png_color_8 sig_bit; png_bytepp row_pointers, begin_row, end_row; unsigned int i; size_t y; /* Find the BMP header. */ for (i = 0; ; ++i) /* skip macbinary header */ { if (fread(bfh, FILEHED_SIZE + BIHSIZE_SIZE, 1, stream) != 1) ++i; else if (bmp_get_word(bfh + BFH_WTYPE) == BMP_SIGNATURE) break; if (fread(bfh, 128 - FILEHED_SIZE - BIHSIZE_SIZE, 1, stream) != 1) ++i; if (i > 0) return 0; /* not a BMP file */ } /* Read the BMP header. */ offbits = bmp_get_dword(bfh + BFH_DOFFBITS); bihsize = bmp_get_dword(bfh + BFH_DBIHSIZE); if ((offbits > PNG_UINT_31_MAX) || (bihsize > PNG_UINT_31_MAX) || (offbits < bihsize + FILEHED_SIZE) || (bihsize != COREHED_SIZE && bihsize < INFOHED_SIZE)) return 0; /* not a BMP file, just a file with a matching signature */ if (bihsize > BMPV5HED_SIZE) { skip = bihsize - BMPV5HED_SIZE; bihsize = BMPV5HED_SIZE; } else skip = 0; if (fread(bih + BIHSIZE_SIZE, bihsize - BIHSIZE_SIZE, 1, stream) != 1) return 0; if (skip > 0) if (fseek(stream, (long)skip, SEEK_CUR) != 0) return 0; skip = offbits - bihsize - FILEHED_SIZE; /* new skip */ topdown = 0; if (bihsize < INFOHED_SIZE) /* OS/2 BMP */ { width = bmp_get_word(bih + BCH_WWIDTH); height = bmp_get_word(bih + BCH_WHEIGHT); pixdepth = bmp_get_word(bih + BCH_WBITCOUNT); compression = BI_RGB; palsize = RGBTRIPLE_SIZE; } else /* Windows BMP */ { width = bmp_get_dword(bih + BIH_LWIDTH); height = bmp_get_dword(bih + BIH_LHEIGHT); pixdepth = bmp_get_word(bih + BIH_WBITCOUNT); compression = bmp_get_dword(bih + BIH_DCOMPRESSION); palsize = RGBQUAD_SIZE; if (height > PNG_UINT_31_MAX) /* top-down BMP */ { height = PNG_UINT_32_MAX - height + 1; topdown = 1; } if (bihsize == INFOHED_SIZE && compression == BI_BITFIELDS) { /* Read the RGB[A] mask. */ i = (skip <= 16) ? (unsigned int)skip : 16; if (fread(bih + B4H_DREDMASK, i, 1, stream) != 1) return 0; bihsize += i; skip -= i; } } memset(rgba_mask, 0, sizeof(rgba_mask)); if (pixdepth > 8) { if (compression == BI_RGB) { if (pixdepth == 16) { compression = BI_BITFIELDS; rgba_mask[0] = 0x7c00; rgba_mask[1] = 0x03e0; rgba_mask[2] = 0x001f; } else /* pixdepth == 24 || pixdepth == 32 */ { rgba_mask[0] = (png_uint_32)0x00ff0000L; rgba_mask[1] = (png_uint_32)0x0000ff00L; rgba_mask[2] = (png_uint_32)0x000000ffL; } } else if (compression == BI_BITFIELDS) { if (bihsize >= INFOHED_SIZE + 12) { rgba_mask[0] = bmp_get_dword(bih + B4H_DREDMASK); rgba_mask[1] = bmp_get_dword(bih + B4H_DGREENMASK); rgba_mask[2] = bmp_get_dword(bih + B4H_DBLUEMASK); } else png_error(png_ptr, "Missing color mask in BMP file"); } if (bihsize >= INFOHED_SIZE + 16) rgba_mask[3] = bmp_get_dword(bih + B4H_DALPHAMASK); } switch (compression) { case BI_RGB: /* Allow pixel depth values 1, 2, 4, 8, 16, 24, 32. * (Although the BMP spec does not mention pixel depth = 2, * it is supported for robustness reasons, at no extra cost.) */ if (pixdepth > 0 && 32 % pixdepth != 0 && pixdepth != 24) pixdepth = 0; break; case BI_RLE8: if (pixdepth != 8) pixdepth = 0; break; case BI_RLE4: if (pixdepth != 4) pixdepth = 0; break; case BI_BITFIELDS: if (pixdepth != 16 && pixdepth != 32) pixdepth = 0; break; case BI_JPEG: png_error(png_ptr, "JPEG-compressed BMP files are not supported"); /* NOTREACHED */ break; case BI_PNG: if (ungetc(getc(stream), stream) == 0) /* IHDR is likely to follow */ png_set_sig_bytes(png_ptr, 8); png_set_read_fn(png_ptr, stream, NULL); png_read_png(png_ptr, info_ptr, 0, NULL); /* TODO: Check for mismatches between the BMP and PNG info. */ return 1; default: png_error(png_ptr, "Unsupported compression method in BMP file"); } /* Check the BMP image parameters. */ if (width == 0 || width > PNG_UINT_31_MAX || height == 0) png_error(png_ptr, "Invalid image dimensions in BMP file"); if (pixdepth == 0) png_error(png_ptr, "Invalid pixel depth in BMP file"); /* Compute the PNG image parameters. */ if (pixdepth <= 8) { palnum = skip / palsize; if (palnum > 256) palnum = 256; skip -= palsize * palnum; rowsize = (width + (32 / pixdepth) - 1) / (32 / pixdepth) * 4; /* rowsize becomes 0 on overflow. */ bit_depth = pixdepth; color_type = (palnum > 0) ? PNG_COLOR_TYPE_PALETTE : PNG_COLOR_TYPE_GRAY; } else { palnum = 0; bit_depth = 8; switch (pixdepth) { case 16: rowsize = (width * 2 + 3) & (~3); break; case 24: rowsize = (width * 3 + 3) & (~3); break; case 32: rowsize = width * 4; break; default: /* never get here */ bit_depth = 0; rowsize = 0; } if (rowsize / width < pixdepth / 8) rowsize = 0; /* overflow */ color_type = (rgba_mask[3] != 0) ? PNG_COLOR_TYPE_RGBA : PNG_COLOR_TYPE_RGB; } if (rowsize == 0) png_error(png_ptr, "Can't handle exceedingly large BMP dimensions"); /* Set the PNG image type. */ png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); if (pixdepth > 8) { for (i = 0; i < 4; ++i) bmp_process_mask(rgba_mask[i], &rgba_sig[i], &rgba_shift[i]); if (rgba_sig[0] == 0 || rgba_sig[1] == 0 || rgba_sig[2] == 0) png_error(png_ptr, "Invalid color mask in BMP file"); if (rgba_sig[0] != 8 || rgba_sig[1] != 8 || rgba_sig[2] != 8 || (rgba_sig[3] != 0 && rgba_sig[3] != 8)) { sig_bit.red = rgba_sig[0]; sig_bit.green = rgba_sig[1]; sig_bit.blue = rgba_sig[2]; sig_bit.alpha = rgba_sig[3]; png_set_sBIT(png_ptr, info_ptr, &sig_bit); } } /* Read the color palette (if applicable). */ if (palnum > 0) { for (i = 0; i < palnum; ++i) { if (fread(rgbq, palsize, 1, stream) != 1) break; palette[i].red = rgbq[RGB_RED]; palette[i].green = rgbq[RGB_GREEN]; palette[i].blue = rgbq[RGB_BLUE]; } png_set_PLTE(png_ptr, info_ptr, palette, i); if (i != palnum) png_error(png_ptr, "Error reading color palette in BMP file"); } /* Allocate memory and read the image data. */ row_pointers = pngx_malloc_rows_extended(png_ptr, info_ptr, rowsize, -1); if (topdown) { begin_row = row_pointers; end_row = row_pointers + height; } else { begin_row = row_pointers + height - 1; end_row = row_pointers - 1; } if (skip > 0) fseek(stream, (long)skip, SEEK_CUR); y = bmp_read_rows(begin_row, end_row, rowsize, compression, stream); /* Postprocess the image data, even if it has not been read entirely. */ if (pixdepth > 8) bmp_to_png_rows(row_pointers, width, height, pixdepth, rgba_sig, rgba_shift); /* Check the result. */ if (y != (size_t)height) png_error(png_ptr, "Error reading BMP file"); return 1; /* one image has been successfully read */ } optipng-0.7.7/src/pngxtern/pngxread.c000066400000000000000000000111321343170417500176200ustar00rootroot00000000000000/* * pngxread.c - libpng external I/O: read utility functions. * Copyright (C) 2003-2011 Cosmin Truta. */ #include "pngxtern.h" #include #include #include #include #define PNGX_INTERNAL #include "pngxpriv.h" static int pngx_sig_is_png(png_structp png_ptr, png_bytep sig, size_t sig_size, png_const_charpp fmt_name_ptr, png_const_charpp fmt_long_name_ptr) { /* The signature of this function differs from the other pngx_sig_is_X() * functions, to allow extra functionality (e.g. customized error messages) * without requiring a full pngx_read_png(). */ static const char pngx_png_standalone_fmt_name[] = "PNG"; static const char pngx_png_datastream_fmt_name[] = "PNG datastream"; static const char pngx_png_standalone_fmt_long_name[] = "Portable Network Graphics"; static const char pngx_png_datastream_fmt_long_name[] = "Portable Network Graphics embedded datastream"; static const png_byte png_file_sig[8] = {137, 80, 78, 71, 13, 10, 26, 10}; static const png_byte mng_file_sig[8] = {138, 77, 78, 71, 13, 10, 26, 10}; static const png_byte png_ihdr_sig[8] = {0, 0, 0, 13, 73, 72, 68, 82}; int has_png_sig; /* Since png_read_png() fails rather abruptly with png_error(), * spend a little more effort to ensure that the format is indeed PNG. * Among other things, look for the presence of IHDR. */ if (sig_size <= 25 + 18) /* size of (IHDR + IDAT) > (12+13) + (12+6) */ return -1; has_png_sig = (memcmp(sig, png_file_sig, 8) == 0); if (memcmp(sig + (has_png_sig ? 8 : 0), png_ihdr_sig, 8) != 0) { /* This is not valid PNG: get as much information as possible. */ if (memcmp(sig, png_file_sig, 4) == 0 && (sig[4] == 10 || sig[4] == 13)) png_error(png_ptr, "PNG file appears to be corrupted by text file conversions"); else if (memcmp(sig, mng_file_sig, 8) == 0) png_error(png_ptr, "MNG decoding is not supported"); /* JNG is handled by the pngxrjpg module. */ return 0; /* not PNG */ } /* Store the format name. */ if (fmt_name_ptr != NULL) { *fmt_name_ptr = has_png_sig ? pngx_png_standalone_fmt_name : pngx_png_datastream_fmt_name; } if (fmt_long_name_ptr != NULL) { *fmt_long_name_ptr = has_png_sig ? pngx_png_standalone_fmt_long_name : pngx_png_datastream_fmt_long_name; } return 1; /* PNG, really! */ } int PNGAPI pngx_read_image(png_structp png_ptr, png_infop info_ptr, png_const_charpp fmt_name_ptr, png_const_charpp fmt_long_name_ptr) { png_byte sig[128]; size_t num; int (*read_fn)(png_structp, png_infop, FILE *); FILE *stream; fpos_t fpos; int result; /* Precondition. */ #ifdef PNG_FLAG_MALLOC_NULL_MEM_OK if (png_ptr->flags & PNG_FLAG_MALLOC_NULL_MEM_OK) png_error(png_ptr, "pngxtern requires a safe allocator"); #endif /* Read the signature bytes. */ stream = (FILE *)png_get_io_ptr(png_ptr); if (fgetpos(stream, &fpos) != 0) png_error(png_ptr, "Can't ftell in input file stream"); num = fread(sig, 1, sizeof(sig), stream); if (fsetpos(stream, &fpos) != 0) png_error(png_ptr, "Can't fseek in input file stream"); /* Try the PNG format first. */ if (pngx_sig_is_png(png_ptr, sig, num, fmt_name_ptr, fmt_long_name_ptr) > 0) { png_read_png(png_ptr, info_ptr, 0, NULL); if (getc(stream) != EOF) { png_warning(png_ptr, "Extraneous data found after IEND"); fseek(stream, 0, SEEK_END); } return 1; } /* Check the signature bytes against other known image formats. */ if (pngx_sig_is_bmp(sig, num, fmt_name_ptr, fmt_long_name_ptr) > 0) read_fn = pngx_read_bmp; else if (pngx_sig_is_gif(sig, num, fmt_name_ptr, fmt_long_name_ptr) > 0) read_fn = pngx_read_gif; else if (pngx_sig_is_jpeg(sig, num, fmt_name_ptr, fmt_long_name_ptr) > 0) read_fn = pngx_read_jpeg; else if (pngx_sig_is_pnm(sig, num, fmt_name_ptr, fmt_long_name_ptr) > 0) read_fn = pngx_read_pnm; else if (pngx_sig_is_tiff(sig, num, fmt_name_ptr, fmt_long_name_ptr) > 0) read_fn = pngx_read_tiff; else return 0; /* not a known image format */ /* Read the image. */ result = read_fn(png_ptr, info_ptr, stream); /* Signature checking may give false positives; reading can still fail. */ if (result <= 0) /* this isn't the format we thought it was */ if (fsetpos(stream, &fpos) != 0) png_error(png_ptr, "Can't fseek in input file stream"); return result; } optipng-0.7.7/src/pngxtern/pngxrgif.c000066400000000000000000000122061343170417500176370ustar00rootroot00000000000000/* * pngxrgif.c - libpng external I/O: GIF reader. * Copyright (C) 2003-2012 Cosmin Truta. */ #include "pngxtern.h" #include "pngxutil.h" #include "gifread.h" #include #include #include #define PNGX_INTERNAL #include "pngxpriv.h" static const char gif_fmt_name[] = "GIF"; static const char gif_fmt_long_name[] = "Graphics Interchange Format"; static const png_byte gif_sig_gif87a[6] = { 0x47, 0x49, 0x46, 0x38, 0x37, 0x61 }; /* "GIF87a" */ static const png_byte gif_sig_gif89a[6] = { 0x47, 0x49, 0x46, 0x38, 0x39, 0x61 }; /* "GIF89a" */ int /* PRIVATE */ pngx_sig_is_gif(png_bytep sig, size_t sig_size, png_const_charpp fmt_name_ptr, png_const_charpp fmt_long_name_ptr) { /* Require at least the GIF signature and the screen descriptor. */ if (sig_size < 6 + 7) return -1; /* insufficient data */ if (memcmp(sig, gif_sig_gif87a, 6) != 0 && memcmp(sig, gif_sig_gif89a, 6) != 0) return 0; /* not GIF */ /* Store the format name. */ if (fmt_name_ptr != NULL) *fmt_name_ptr = gif_fmt_name; if (fmt_long_name_ptr != NULL) *fmt_long_name_ptr = gif_fmt_long_name; return 1; /* GIF */ } /* FIXME: Not thread-safe. */ static png_structp err_png_ptr; static struct GIFImage *err_gif_image_ptr; static struct GIFExtension *err_gif_ext_ptr; static void pngx_gif_error(const char *msg) { if (err_gif_image_ptr != NULL) GIFDestroyImage(err_gif_image_ptr); if (err_gif_ext_ptr != NULL) GIFDestroyExtension(err_gif_ext_ptr); png_error(err_png_ptr, msg); } static void pngx_gif_warning(const char *msg) { png_warning(err_png_ptr, msg); } static void pngx_set_gif_palette(png_structp png_ptr, png_infop info_ptr, unsigned char *color_table, unsigned int num_colors) { png_color palette[256]; unsigned int i; PNGX_ASSERT(color_table != NULL); PNGX_ASSERT(num_colors <= 256); for (i = 0; i < num_colors; ++i) { palette[i].red = color_table[3 * i]; palette[i].green = color_table[3 * i + 1]; palette[i].blue = color_table[3 * i + 2]; } png_set_PLTE(png_ptr, info_ptr, palette, (int)num_colors); } static void pngx_set_gif_transparent(png_structp png_ptr, png_infop info_ptr, unsigned int transparent) { png_byte trans[256]; unsigned int i; PNGX_ASSERT(transparent < 256); for (i = 0; i < transparent; ++i) trans[i] = 255; trans[transparent] = 0; png_set_tRNS(png_ptr, info_ptr, trans, (int)transparent + 1, NULL); } int /* PRIVATE */ pngx_read_gif(png_structp png_ptr, png_infop info_ptr, FILE *stream) { /* GIF-specific data */ struct GIFScreen screen; struct GIFImage image; struct GIFExtension ext; struct GIFGraphicCtlExt graphicExt; int blockCode; unsigned char *colorTable; unsigned int numColors; unsigned int transparent; unsigned int numImages; /* PNG-specific data */ png_uint_32 width, height; png_bytepp row_pointers; /* Set up the custom error handling. */ GIFError = pngx_gif_error; GIFWarning = pngx_gif_warning; err_png_ptr = png_ptr; err_gif_image_ptr = NULL; err_gif_ext_ptr = NULL; /* Read the GIF screen. */ GIFReadScreen(&screen, stream); width = screen.Width; height = screen.Height; /* Set the PNG image type. */ png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* Allocate memory. */ row_pointers = pngx_malloc_rows(png_ptr, info_ptr, (int)screen.Background); /* Complete the initialization of the GIF reader. */ GIFInitImage(&image, &screen, row_pointers); err_gif_image_ptr = ℑ GIFInitExtension(&ext, &screen, 256); err_gif_ext_ptr = &ext; numImages = 0; transparent = (unsigned int)(-1); /* Iterate over the GIF file. */ for ( ; ; ) { blockCode = GIFReadNextBlock(&image, &ext, stream); if (blockCode == GIF_IMAGE) /* ',' */ { if (image.Rows != NULL) { /* Complete the PNG info. */ if (image.InterlaceFlag) pngx_set_interlace_type(png_ptr, info_ptr, PNG_INTERLACE_ADAM7); GIFGetColorTable(&colorTable, &numColors, &image); pngx_set_gif_palette(png_ptr, info_ptr, colorTable, numColors); if (transparent < 256) pngx_set_gif_transparent(png_ptr, info_ptr, transparent); /* Inform the GIF routines not to read the upcoming images. */ image.Rows = NULL; } ++numImages; } else if (blockCode == GIF_EXTENSION) /* '!' */ { if (ext.Label == GIF_GRAPHICCTL) { GIFGetGraphicCtl(&graphicExt, &ext); if (image.Rows != NULL && graphicExt.TransparentFlag) { if (transparent >= 256) transparent = graphicExt.Transparent; } } } else if (blockCode == GIF_TERMINATOR) /* ';' */ break; } if (image.Rows != NULL) png_error(png_ptr, "No image in GIF file"); GIFDestroyImage(&image); GIFDestroyExtension(&ext); return numImages; } optipng-0.7.7/src/pngxtern/pngxrjpg.c000066400000000000000000000070671343170417500176630ustar00rootroot00000000000000/* * pngxrjpg.c - libpng external I/O: JPEG reader stub. * Copyright (C) 2006-2011 Cosmin Truta. * * From the information-theoretic point of view, JPEG-to-PNG conversion * is not a worthwhile task. Moreover, a JPEG decoder would add a * significant overhead to the application. As such, we provide a stub * that recognizes the JPEG format, without actually processing it. */ #include "pngxtern.h" #include #include #define PNGX_INTERNAL #include "pngxpriv.h" /* * These are the various JPEG format signatures. * * FF D8 FF E0 ........................... JFIF * FF D8 FF E1 ........................... EXIF * FF D8 FF F7 ........................... JPEG-LS * FF 4F FF 51 ........................... JPEG-2000 codestream * 00 00 00 0C 6A 50 20 20 0D 0A 87 0A ... JPEG-2000 .jp2 * 8B 4A 4E 47 0D 0A 1A 0A ............... JNG * 00 00 00 10 4A 48 44 52 ............... JNG datastream * etc. */ #define JPEG_SIG_JP2_SIZE 12 #define JPEG_SIG_JPC_SIZE 4 #define JPEG_SIG_JNG_SIZE 8 #define JPEG_SIG_SIZE_MAX 12 static const png_byte jpeg_sig_jp2[JPEG_SIG_JP2_SIZE] = { 0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a }; static const png_byte jpeg_sig_jpc[JPEG_SIG_JPC_SIZE] = { 0xff, 0x4f, 0xff, 0x51 }; static const png_byte jpeg_sig_jng[JPEG_SIG_JNG_SIZE] = { 0x8b, 0x4a, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a }; static const png_byte jpeg_sig_jng_jhdr[JPEG_SIG_JNG_SIZE] = { 0x00, 0x00, 0x00, 0x1a, 0x4a, 0x48, 0x44, 0x52 }; int /* PRIVATE */ pngx_sig_is_jpeg(png_bytep sig, size_t sig_size, png_const_charpp fmt_name_ptr, png_const_charpp fmt_long_name_ptr) { const char *fmt; unsigned int marker; int result; if (sig_size < JPEG_SIG_SIZE_MAX) return -1; if (sig[0] == 0xff && sig[1] == 0xd8 && sig[2] == 0xff) { marker = 0xff00U | sig[3]; if ((marker >= 0xffc0U && marker <= 0xffcfU) || (marker >= 0xffdaU && marker <= 0xfffeU)) { fmt = "JPEG"; result = 1; /* JFIF, EXIF, JPEG-LS, codestream, etc. */ } else return 0; /* not JPEG */ } else if (memcmp(sig, jpeg_sig_jp2, JPEG_SIG_JP2_SIZE) == 0 || memcmp(sig, jpeg_sig_jpc, JPEG_SIG_JPC_SIZE) == 0) { fmt = "JPEG-2000"; result = 2; /* .jp2 or JPEG-2000 codestream */ } else if (memcmp(sig, jpeg_sig_jng, JPEG_SIG_JNG_SIZE) == 0 || memcmp(sig, jpeg_sig_jng_jhdr, JPEG_SIG_JNG_SIZE) == 0) { fmt = "JNG"; result = 3; /* JNG, standalone or datastream */ } else return 0; /* not JPEG */ /* Store the format name. */ if (fmt_name_ptr != NULL) *fmt_name_ptr = fmt; if (fmt_long_name_ptr != NULL) *fmt_long_name_ptr = fmt; return result; } int /* PRIVATE */ pngx_read_jpeg(png_structp png_ptr, png_infop info_ptr, FILE *stream) { png_byte buf[JPEG_SIG_SIZE_MAX]; int sig_code; if (fread(buf, JPEG_SIG_SIZE_MAX, 1, stream) != 1) return 0; /* not a JPEG file */ sig_code = pngx_sig_is_jpeg(buf, JPEG_SIG_SIZE_MAX, NULL, NULL); /* TODO: Use the format names passed by pngx_sig_is_jpeg. */ switch (sig_code) { case 1: png_error(png_ptr, "JPEG decoding is not supported"); /* NOTREACHED */ break; case 2: png_error(png_ptr, "JPEG-2000 decoding is not supported"); /* NOTREACHED */ break; case 3: png_error(png_ptr, "JNG (JPEG) decoding is not supported"); /* NOTREACHED */ break; } if (info_ptr == NULL) /* dummy, keep compilers happy */ return 0; return 0; /* always fail */ } optipng-0.7.7/src/pngxtern/pngxrpnm.c000066400000000000000000000155361343170417500176750ustar00rootroot00000000000000/* * pngxrpnm.c - libpng external I/O: PNM reader. * Copyright (C) 2003-2012 Cosmin Truta. */ #include "pngxtern.h" #include "pngxutil.h" #include "pnmio.h" #include #include #include #define PNGX_INTERNAL #include "pngxpriv.h" #if UINT_MAX >= 0x7fffffffUL #define PNGX_PNM_LENGTH_MAX 0x7fffffffU #else #define PNGX_PNM_LENGTH_MAX UINT_MAX #endif static const char pbm_fmt_name[] = "PBM"; static const char pgm_fmt_name[] = "PGM"; static const char ppm_fmt_name[] = "PPM"; static const char pam_fmt_name[] = "PAM"; static const char pbm_fmt_long_name[] = "Portable Bitmap"; static const char pgm_fmt_long_name[] = "Portable Graymap"; static const char ppm_fmt_long_name[] = "Portable Pixmap"; static const char pam_fmt_long_name[] = "Portable Anymap"; int /* PRIVATE */ pngx_sig_is_pnm(png_bytep sig, size_t sig_size, png_const_charpp fmt_name_ptr, png_const_charpp fmt_long_name_ptr) { static const char *fmt_names[] = { pbm_fmt_name, pgm_fmt_name, ppm_fmt_name, pbm_fmt_name, pgm_fmt_name, ppm_fmt_name, pam_fmt_name }; static const char *fmt_long_names[] = { pbm_fmt_long_name, pgm_fmt_long_name, ppm_fmt_long_name, pbm_fmt_long_name, pgm_fmt_long_name, ppm_fmt_long_name, pam_fmt_long_name }; /* Require at least the PNM magic signature and the trailing whitespace. */ if (sig_size < 4) return -1; /* insufficient data */ if (sig[0] != 'P' || sig[1] < '1' || sig[1] > '7') return 0; /* not PNM */ if (sig[2] != ' ' && sig[2] != '\t' && sig[2] != '\n' && sig[2] != '\r' && sig[2] != '#') return 0; /* not PNM */ /* Store the format name. */ if (fmt_name_ptr != NULL) *fmt_name_ptr = fmt_names[sig[1] - '1']; if (fmt_long_name_ptr != NULL) *fmt_long_name_ptr = fmt_long_names[sig[1] - '1']; return 1; /* PNM */ } static int pnm_fpeek_eof(pnm_struct *pnm_ptr, FILE *stream) { int ch; if (pnm_ptr->format >= PNM_P1 && pnm_ptr->format <= PNM_P3) { do { ch = getc(stream); if (ch == '#') /* skip comments */ { do ch = getc(stream); while (ch != EOF && ch != '\n' && ch != '\r'); } if (ch == EOF) return 1; } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'); } else { ch = getc(stream); if (ch == EOF) return 1; } ungetc(ch, stream); return 0; } int /* PRIVATE */ pngx_read_pnm(png_structp png_ptr, png_infop info_ptr, FILE *stream) { pnm_struct pnminfo; unsigned int format, depth, width, height, maxval; unsigned int max_width, num_samples, sample_size; unsigned int *pnmrow; size_t row_size; png_bytepp row_pointers; png_color_8 sig_bit; unsigned int i, j; int failed, overflow; /* Read the PNM header. */ if (pnm_fget_header(&pnminfo, stream) != 1) return 0; /* not PNM */ format = pnminfo.format; depth = pnminfo.depth; width = pnminfo.width; height = pnminfo.height; maxval = pnminfo.maxval; if (format > PNM_P6) png_error(png_ptr, "Can't handle PNM formats newer than PPM (\"P6\")"); max_width = (sizeof(size_t) <= sizeof(unsigned int)) ? UINT_MAX / sizeof(unsigned int) / depth : UINT_MAX; #if UINT_MAX > PNGX_PNM_LENGTH_MAX if (max_width > PNGX_PNM_LENGTH_MAX) max_width = PNGX_PNM_LENGTH_MAX; #endif if (width > max_width) png_error(png_ptr, "Can't handle exceedingly large PNM dimensions"); sample_size = 1; row_size = num_samples = depth * width; if (maxval > 65535) png_error(png_ptr, "Can't handle PNM samples larger than 16 bits"); else if (maxval > 255) { sample_size = 2; row_size *= 2; } /* Set the PNG image type. */ png_set_IHDR(png_ptr, info_ptr, width, height, (maxval <= 255) ? 8 : 16, (depth == 1) ? PNG_COLOR_TYPE_GRAY : PNG_COLOR_TYPE_RGB, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); for (i = 1, j = 2; j - 1 < maxval; ++i, j <<= 1) { } if (j - 1 != maxval) png_warning(png_ptr, "Possibly inexact sample conversion from PNM to PNG"); else if (i % 8 != 0 && (depth > 1 || 8 % i != 0)) { sig_bit.red = sig_bit.green = sig_bit.blue = sig_bit.gray = (png_byte)i; sig_bit.alpha = 0; png_set_sBIT(png_ptr, info_ptr, &sig_bit); } /* Allocate memory. */ row_pointers = pngx_malloc_rows(png_ptr, info_ptr, -1); if ((format >= PNM_P4) && (maxval == 255 || maxval == 65535)) pnmrow = NULL; /* can read raw data directly into row_pointers */ else pnmrow = (unsigned int *) png_malloc(png_ptr, num_samples * sizeof(unsigned int)); /* Read the image data. */ failed = 0; overflow = 0; if (pnmrow != NULL) { for (i = 0; i < height; ++i) { if (pnm_fget_values(&pnminfo, pnmrow, 1, stream) <= 0) failed = 1; /* Transfer the samples, even on partial (unsuccessful) reads. */ if (maxval <= 255) { for (j = 0; j < num_samples; ++j) { unsigned int val = pnmrow[j]; if (val > maxval) { val = 255; overflow = 1; } else if (maxval != 255) val = (val * 255 + maxval/2) / maxval; row_pointers[i][j] = (png_byte)val; } } else /* maxval > 255 */ { for (j = 0; j < num_samples; ++j) { png_uint_32 val = pnmrow[j]; if (val > maxval) { val = 65535; overflow = 1; } else if (maxval != 65535) val = (val * 65535 + maxval/2) / maxval; row_pointers[i][2 * j] = (png_byte)(val >> 8); row_pointers[i][2 * j + 1] = (png_byte)(val & 0xff); } } if (failed) break; } } else /* read the raw data directly */ { for (i = 0; i < height; ++i) { if (pnm_fget_bytes(&pnminfo, row_pointers[i], sample_size, 1, stream) <= 0) { failed = 1; break; } } } /* Wipe out the portion left unread. */ for ( ; i < height; ++i) memset(row_pointers[i], 0, row_size); /* Deallocate the temporary row buffer. */ if (pnmrow != NULL) png_free(png_ptr, pnmrow); /* Check the results. */ if (overflow) png_warning(png_ptr, "Overflow in PNM samples"); if (failed) png_error(png_ptr, "Error in PNM image file"); else if (!pnm_fpeek_eof(&pnminfo, stream)) png_warning(png_ptr, "Extraneous data found after PNM image"); /* FIXME: A PNM file can have more than one image. */ return 1; /* one image has been successfully read */ } optipng-0.7.7/src/pngxtern/pngxrtif.c000066400000000000000000000116421343170417500176570ustar00rootroot00000000000000/* * pngxrtif.c - libpng external I/O: TIFF reader. * Copyright (C) 2006-2012 Cosmin Truta. */ #include "pngxtern.h" #include "pngxutil.h" #include "minitiff.h" #include #include #define PNGX_INTERNAL #include "pngxpriv.h" /* * The TIFF format name. */ static const char tiff_fmt_name[] = "TIFF"; static const char tiff_fmt_long_name[] = "Tagged Image File Format"; int /* PRIVATE */ pngx_sig_is_tiff(png_bytep sig, size_t sig_size, png_const_charpp fmt_name_ptr, png_const_charpp fmt_long_name_ptr) { /* Require at least the TIFF signature. */ if (sig_size < 8) return -1; /* insufficient data */ if (memcmp(sig, minitiff_sig_m, 4) != 0 && memcmp(sig, minitiff_sig_i, 4) != 0) return 0; /* not TIFF */ /* Store the format name. */ if (fmt_name_ptr != NULL) *fmt_name_ptr = tiff_fmt_name; if (fmt_long_name_ptr != NULL) *fmt_long_name_ptr = tiff_fmt_long_name; return 1; /* TIFF */ } /* FIXME: Not thread-safe. */ static png_structp err_png_ptr = NULL; static unsigned int num_extra_images; static void pngx_tiff_error(const char *msg) { png_error(err_png_ptr, msg); } static void pngx_tiff_warning(const char *msg) { /* FIXME: * Inspection of warning messages is fragile, but is * required by the limitations of minitiff version 0.1. */ if (strstr(msg, "multi-image") != NULL) ++num_extra_images; #if 0 /* Metadata is not imported, so warnings need not be shown. */ png_warning(err_png_ptr, msg); #endif } int /* PRIVATE */ pngx_read_tiff(png_structp png_ptr, png_infop info_ptr, FILE *stream) { struct minitiff_info tiff_info; unsigned int width, height, pixel_size, sample_depth, sample_max; int color_type; int sample_overflow; png_bytepp row_pointers; png_bytep row; unsigned int i, j, k; err_png_ptr = png_ptr; num_extra_images = 0; minitiff_init_info(&tiff_info); tiff_info.error_handler = pngx_tiff_error; tiff_info.warning_handler = pngx_tiff_warning; minitiff_read_info(&tiff_info, stream); minitiff_validate_info(&tiff_info); width = (unsigned int)tiff_info.width; height = (unsigned int)tiff_info.height; pixel_size = tiff_info.samples_per_pixel; sample_depth = tiff_info.bits_per_sample; switch (pixel_size) { case 1: color_type = PNG_COLOR_TYPE_GRAY; break; case 2: color_type = PNG_COLOR_TYPE_GRAY_ALPHA; break; case 3: color_type = PNG_COLOR_TYPE_RGB; break; case 4: color_type = PNG_COLOR_TYPE_RGB_ALPHA; break; default: png_error(png_ptr, "Unsupported TIFF color space"); /* NOTREACHED */ return 0; /* avoid "uninitialized color_type" warning */ } if (sample_depth > 16) png_error(png_ptr, "Unsupported TIFF sample depth"); sample_max = (1 << sample_depth) - 1; sample_overflow = 0; png_set_IHDR(png_ptr, info_ptr, width, height, (sample_depth <= 8) ? 8 : 16, color_type, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); row_pointers = pngx_malloc_rows(png_ptr, info_ptr, 0); if (sample_depth <= 8) { for (i = 0; i < height; ++i) { row = row_pointers[i]; minitiff_read_row(&tiff_info, row, i, stream); if (sample_depth < 8) { for (j = 0; j < pixel_size * width; ++j) { unsigned int b = row[j]; if (b > sample_max) { b = sample_max; sample_overflow = 1; } row[j] = (png_byte)((b * 255 + sample_max / 2) / sample_max); } } if (tiff_info.photometric == 0) { for (j = 0; j < pixel_size * width; ++j) row[j] = (png_byte)(255 - row[j]); } } } else { for (i = 0; i < height; ++i) { row = row_pointers[i]; minitiff_read_row(&tiff_info, row, i, stream); if (tiff_info.byte_order == 'I') { /* "Intel" byte order => swap row bytes */ for (j = k = 0; j < pixel_size * width; ++j, k+=2) { png_byte b = row[k]; row[k] = row[k + 1]; row[k + 1] = b; } } if (sample_depth < 16) { for (j = k = 0; k < pixel_size * width; ++j, k+=2) { unsigned int b = (row[k] << 8) + row[k + 1]; if (b > sample_max) { b = sample_max; sample_overflow = 1; } b = (b * 65535U + sample_max / 2) / sample_max; row[k] = (png_byte)(b >> 8); row[k + 1] = (png_byte)(b & 255); } } } } if (sample_overflow) png_warning(png_ptr, "Overflow in TIFF samples"); minitiff_destroy_info(&tiff_info); return 1 + num_extra_images; } optipng-0.7.7/src/pngxtern/pngxset.c000066400000000000000000000045001343170417500175010ustar00rootroot00000000000000/* * pngxset.c - libpng extension: additional image info storage. * * Copyright (C) 2003-2011 Cosmin Truta. * This software is distributed under the same licensing and warranty terms * as libpng. */ #include "pngxutil.h" /* * NOTE: * There is a discrepancy between the parameter names used in * this module vs. the PNG specification. * The PNG specification uses the terms "compression method", * "filter method" and "interlace method", while this module * uses the terms, respectively, "compression type", "filter type" * and "interlace type", following the libpng naming conventions. */ void PNGAPI pngx_set_compression_type(png_structp png_ptr, png_infop info_ptr, int compression_type) { png_uint_32 width, height; int bit_depth, color_type, interlace_type, filter_type; int old_compression_type; if (!png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &old_compression_type, &filter_type)) return; if (compression_type == old_compression_type) return; png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type, compression_type, filter_type); } void PNGAPI pngx_set_filter_type(png_structp png_ptr, png_infop info_ptr, int filter_type) { png_uint_32 width, height; int bit_depth, color_type, interlace_type, compression_type; int old_filter_type; if (!png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, &compression_type, &old_filter_type)) return; if (filter_type == old_filter_type) return; png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type, compression_type, filter_type); } void PNGAPI pngx_set_interlace_type(png_structp png_ptr, png_infop info_ptr, int interlace_type) { png_uint_32 width, height; int bit_depth, color_type, compression_type, filter_type; int old_interlace_type; if (!png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &old_interlace_type, &compression_type, &filter_type)) return; if (interlace_type == old_interlace_type) return; png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type, compression_type, filter_type); } optipng-0.7.7/src/pngxtern/pngxtern.h000066400000000000000000000032121343170417500176620ustar00rootroot00000000000000/* * pngxtern.h - external file format processing for libpng. * * Copyright (C) 2003-2011 Cosmin Truta. * This software is distributed under the same licensing and warranty terms * as libpng. */ #ifndef PNGXTERN_H #define PNGXTERN_H #include "png.h" #ifdef __cplusplus extern "C" { #endif /* * Read the contents of an image file and store it into the given * libpng structures. * * The currently recognized file formats are: * PNG (standalone), PNG (datastream), BMP, GIF, PNM and TIFF. * * The function reads either the first or the most relevant image, * depending on the format. For example, embedded thumbnails, if * present, are skipped. * * On success, the function returns the number of images contained * by the image file, which can be greater than 1 for formats like * GIF or TIFF. If the function finds more than one image but does * not perform a complete image count, it returns an upper bound. * The function stores the short and/or the long format name * (e.g. "PPM", "Portable Pixmap") into the given name pointers, * if they are non-null. * * If the function fails to detect a known format, it rewinds the * FILE* stream stored in io_ptr and returns 0. * On other errors (e.g. read error or decoding error), the function * issues a png_error(). * * This function requires io_ptr to be a fseek-able FILE*. * It does not work with generic I/O routines. */ int PNGAPI pngx_read_image(png_structp png_ptr, png_infop info_ptr, png_const_charpp fmt_name_ptr, png_const_charpp fmt_long_name_ptr); #ifdef __cplusplus } /* extern "C" */ #endif #endif /* PNGXTERN_H */ optipng-0.7.7/src/pngxtern/pngxutil.h000066400000000000000000000073321343170417500176760ustar00rootroot00000000000000/* * pngxutil.h - libpng extension utilities. * * Copyright (C) 2003-2011 Cosmin Truta. * This software is distributed under the same licensing and warranty terms * as libpng. */ #ifndef PNGXUTIL_H #define PNGXUTIL_H #include "png.h" #ifdef __cplusplus extern "C" { #endif /* Store data into the info structure. */ void PNGAPI pngx_set_compression_type (png_structp png_ptr, png_infop info_ptr, int compression_type); void PNGAPI pngx_set_filter_type (png_structp png_ptr, png_infop info_ptr, int filter_type); void PNGAPI pngx_set_interlace_type (png_structp png_ptr, png_infop info_ptr, int interlace_type); #if PNG_LIBPNG_VER >= 10400 typedef png_alloc_size_t pngx_alloc_size_t; #else /* Compatibility backport of png_alloc_size_t */ typedef png_uint_32 pngx_alloc_size_t; #endif #ifdef PNG_INFO_IMAGE_SUPPORTED /* Allocate memory for the row pointers. * Use filler to initialize the rows if it is non-negative. * On success return the newly-allocated row pointers. * On failure issue a png_error() or return NULL, * depending on the status of PNG_FLAG_MALLOC_NULL_MEM_OK. */ png_bytepp PNGAPI pngx_malloc_rows (png_structp png_ptr, png_infop info_ptr, int filler); png_bytepp PNGAPI pngx_malloc_rows_extended (png_structp png_ptr, png_infop info_ptr, pngx_alloc_size_t min_row_size, int filler); #endif /* * I/O states were introduced in libpng-1.4.0, but they can be reliably used * starting with libpng-1.4.5 only. */ #if PNG_LIBPNG_VER >= 10405 #ifndef PNG_IO_STATE_SUPPORTED #error This module requires libpng with PNG_IO_STATE_SUPPORTED #endif #define pngx_get_io_state png_get_io_state #define pngx_get_io_chunk_name png_get_io_chunk_name #define pngx_set_read_fn png_set_read_fn #define pngx_set_write_fn png_set_write_fn #define pngx_write_sig png_write_sig #define PNGX_IO_NONE PNG_IO_NONE #define PNGX_IO_READING PNG_IO_READING #define PNGX_IO_WRITING PNG_IO_WRITING #define PNGX_IO_SIGNATURE PNG_IO_SIGNATURE #define PNGX_IO_CHUNK_HDR PNG_IO_CHUNK_HDR #define PNGX_IO_CHUNK_DATA PNG_IO_CHUNK_DATA #define PNGX_IO_CHUNK_CRC PNG_IO_CHUNK_CRC #define PNGX_IO_MASK_OP PNG_IO_MASK_OP #define PNGX_IO_MASK_LOC PNG_IO_MASK_LOC #else /* PNG_LIBPNG_VER < 10405 */ /* Compatibility backports of functions added to libpng 1.4 */ png_uint_32 PNGAPI pngx_get_io_state(png_structp png_ptr); png_bytep PNGAPI pngx_get_io_chunk_name(png_structp png_ptr); /* Note: although these backports have several limitations in comparison * to the actual libpng 1.4 functions, they work properly in OptiPNG, * as long as that they are used in conjunction with the wrappers below. */ /* Compatibility wrappers for old libpng functions */ void PNGAPI pngx_set_read_fn (png_structp png_ptr, png_voidp io_ptr, png_rw_ptr read_data_fn); void PNGAPI pngx_set_write_fn (png_structp png_ptr, png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn); void PNGAPI pngx_write_sig(png_structp png_ptr); /* Flags returned by png_get_io_state() */ #define PNGX_IO_NONE 0x0000 /* no I/O at this moment */ #define PNGX_IO_READING 0x0001 /* currently reading */ #define PNGX_IO_WRITING 0x0002 /* currently writing */ #define PNGX_IO_SIGNATURE 0x0010 /* currently at the file signature */ #define PNGX_IO_CHUNK_HDR 0x0020 /* currently at the chunk header */ #define PNGX_IO_CHUNK_DATA 0x0040 /* currently at the chunk data */ #define PNGX_IO_CHUNK_CRC 0x0080 /* currently at the chunk crc */ #define PNGX_IO_MASK_OP 0x000f /* current operation: reading/writing */ #define PNGX_IO_MASK_LOC 0x00f0 /* current location: sig/hdr/data/crc */ #endif #ifdef __cplusplus } /* extern "C" */ #endif #endif /* PNGXUTIL_H */ optipng-0.7.7/src/pnmio/000077500000000000000000000000001343170417500151235ustar00rootroot00000000000000optipng-0.7.7/src/pnmio/Makefile.in000066400000000000000000000012011343170417500171620ustar00rootroot00000000000000.PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = @CC@ CFLAGS = @CFLAGS@ CPP = @CPP@ CPPFLAGS = @CPPFLAGS@ LD = @LD@ LDFLAGS = @LDFLAGS@ AR = @AR@ ARFLAGS = @ARFLAGS@ RANLIB = @RANLIB@ LIBS = @LIBS@ RM_F = @RM_F@ PNMIO_LIB = libpnmio.a PNMIO_OBJS = pnmin.o pnmout.o pnmutil.o all: $(PNMIO_LIB) test: check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< $(PNMIO_LIB): $(PNMIO_OBJS) $(AR) $(ARFLAGS) $@ $(PNMIO_OBJS) $(RANLIB) $@ pnmin.o: pnmin.c pnmio.h pnmout.o: pnmout.c pnmio.h pnmutil.o: pnmutil.c pnmio.h clean: -$(RM_F) $(PNMIO_LIB) $(PNMIO_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/pnmio/README.optipng.txt000066400000000000000000000001671343170417500203040ustar00rootroot00000000000000Name: pnmio Summary: Simple I/O interface to the PNM image file format Author: Cosmin Truta Version: 0.3 License: zlib optipng-0.7.7/src/pnmio/build/000077500000000000000000000000001343170417500162225ustar00rootroot00000000000000optipng-0.7.7/src/pnmio/build/bcc32.mk000066400000000000000000000012761343170417500174550ustar00rootroot00000000000000# bcc32.mk # Generated from Makefile.in # Preconfigured for Borland C++ # # Usage: make -f build\bcc32.mk CC = bcc32 CFLAGS = -O2 -d -k- -w CPP = #cpp32 -P- CPPFLAGS = LD = $(CC) LDFLAGS = $(CFLAGS) AR = tlib ARFLAGS = /C LIBS = #noeh32.lib RM_F = del /q PNMIO_LIB = pnmio.lib PNMIO_OBJS = pnmin.obj pnmout.obj pnmutil.obj PNMIO_LIBOBJS = +pnmin.obj +pnmout.obj +pnmutil.obj all: $(PNMIO_LIB) test: check: test .c.obj: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o$@ $< $(PNMIO_LIB): $(PNMIO_OBJS) $(AR) $(ARFLAGS) $@ $(PNMIO_LIBOBJS) pnmin.obj: pnmin.c pnmio.h pnmout.obj: pnmout.c pnmio.h pnmutil.obj: pnmutil.c pnmio.h clean: -$(RM_F) $(PNMIO_LIB) $(PNMIO_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/pnmio/build/clang.mk000066400000000000000000000013201343170417500176330ustar00rootroot00000000000000# clang.mk # Generated from Makefile.in # Preconfigured for clang # # Usage: make -f build/clang.mk .PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = clang CFLAGS = -O2 -Wall -Wextra CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s AR = ar ARFLAGS = cru RANLIB = ranlib LIBS = RM_F = rm -f PNMIO_LIB = libpnmio.a PNMIO_OBJS = pnmin.o pnmout.o pnmutil.o all: $(PNMIO_LIB) test: check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< $(PNMIO_LIB): $(PNMIO_OBJS) $(AR) $(ARFLAGS) $@ $(PNMIO_OBJS) $(RANLIB) $@ pnmin.o: pnmin.c pnmio.h pnmout.o: pnmout.c pnmio.h pnmutil.o: pnmutil.c pnmio.h clean: -$(RM_F) $(PNMIO_LIB) $(PNMIO_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/pnmio/build/gcc.mk000066400000000000000000000013101343170417500173020ustar00rootroot00000000000000# gcc.mk # Generated from Makefile.in # Preconfigured for gcc # # Usage: make -f build/gcc.mk .PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = gcc CFLAGS = -O2 -Wall -Wextra CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s AR = ar ARFLAGS = cru RANLIB = ranlib LIBS = RM_F = rm -f PNMIO_LIB = libpnmio.a PNMIO_OBJS = pnmin.o pnmout.o pnmutil.o all: $(PNMIO_LIB) test: check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< $(PNMIO_LIB): $(PNMIO_OBJS) $(AR) $(ARFLAGS) $@ $(PNMIO_OBJS) $(RANLIB) $@ pnmin.o: pnmin.c pnmio.h pnmout.o: pnmout.c pnmio.h pnmutil.o: pnmutil.c pnmio.h clean: -$(RM_F) $(PNMIO_LIB) $(PNMIO_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/pnmio/build/unix.mk000066400000000000000000000013051343170417500175350ustar00rootroot00000000000000# unix.mk # Generated from Makefile.in # Preconfigured for Unix (generic) # # Usage: make -f build/unix.mk .PHONY: all test check clean distclean .PRECIOUS: Makefile .SUFFIXES: .c .o .a CC = cc CFLAGS = -O CPP = $(CC) -E CPPFLAGS = LD = $(CC) LDFLAGS = -s AR = ar ARFLAGS = cru RANLIB = ranlib LIBS = RM_F = rm -f PNMIO_LIB = libpnmio.a PNMIO_OBJS = pnmin.o pnmout.o pnmutil.o all: $(PNMIO_LIB) test: check: test .c.o: $(CC) -c $(CPPFLAGS) $(CFLAGS) -o $@ $< $(PNMIO_LIB): $(PNMIO_OBJS) $(AR) $(ARFLAGS) $@ $(PNMIO_OBJS) $(RANLIB) $@ pnmin.o: pnmin.c pnmio.h pnmout.o: pnmout.c pnmio.h pnmutil.o: pnmutil.c pnmio.h clean: -$(RM_F) $(PNMIO_LIB) $(PNMIO_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/pnmio/build/visualc.mk000066400000000000000000000013151343170417500202210ustar00rootroot00000000000000# visualc.mk # Generated from Makefile.in # Preconfigured for Microsoft Visual C++ # # Usage: nmake -f build\visualc.mk CC = cl -nologo CFLAGS = -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE -MD -O2 -W4 CPP = cl -nologo -E CPPFLAGS = LD = link -nologo LDFLAGS = AR = lib -nologo ARFLAGS = LIBS = RM_F = del /q PNMIO_LIB = pnmio.lib PNMIO_OBJS = pnmin.obj pnmout.obj pnmutil.obj all: $(PNMIO_LIB) test: check: test .c.obj: $(CC) -c $(CPPFLAGS) $(CFLAGS) -Fo$@ $< $(PNMIO_LIB): $(PNMIO_OBJS) $(AR) $(ARFLAGS) -out:$@ $(PNMIO_OBJS) pnmin.obj: pnmin.c pnmio.h pnmout.obj: pnmout.c pnmio.h pnmutil.obj: pnmutil.c pnmio.h clean: -$(RM_F) $(PNMIO_LIB) $(PNMIO_OBJS) distclean: clean -$(RM_F) Makefile optipng-0.7.7/src/pnmio/pnmin.c000066400000000000000000000234201343170417500164110ustar00rootroot00000000000000/** * pnmin.c * PNM file input. * * Copyright (C) 2002-2008 Cosmin Truta. * This file is part of the pnmio library, distributed under the zlib license. * For conditions of distribution and use, see copyright notice in pnmio.h. **/ #include #include #include #include #include #include "pnmio.h" /** * Checks if the character is a space: ' ', '\t', '\n' or '\r'. **/ #define pnm_is_space(ch) \ ((ch) == ' ' || (ch) == '\t' || (ch) == '\n' || (ch) == '\r') /** * Checks if the character is a digit: '0' .. '9'. **/ #define pnm_is_digit(ch) \ ((ch) >= '0' && (ch) <= '9') /** * Reads a character from a file stream. * Comment sequences starting with '#' are skipped until the end of line. * End of line sequences (LF, CR, CR+LF) are translated to '\n'. * Returns the character read, or EOF on input failure. **/ static int pnm_fget_char(FILE *stream) { int ch = getc(stream); /* skip the comments */ if (ch == '#') { do { ch = getc(stream); } while (ch != EOF && ch != '\n' && ch != '\r'); } /* translate the line endings */ if (ch == '\r') { ch = getc(stream); if (ch != '\n') { ungetc(ch, stream); ch = '\n'; } } return ch; } /** * Reads (scans) an unsigned integer from a file stream. * Returns 1 on success, 0 on matching failure, or EOF on input failure. **/ static int pnm_fscan_uint(FILE *stream, unsigned int *value) { int ch; unsigned int tmp; /* skip the leading whitespaces */ do { ch = pnm_fget_char(stream); } while (pnm_is_space(ch)); if (ch == EOF) /* input failure */ return EOF; if (!pnm_is_digit(ch)) /* matching failure */ { ungetc(ch, stream); return 0; } /* read the value */ *value = 0; do { tmp = *value * 10 + (ch - '0'); if (tmp >= *value) *value = tmp; else /* overflow */ { *value = UINT_MAX; errno = ERANGE; } ch = getc(stream); } while (pnm_is_digit(ch)); /* put back the trailing non-whitespace, if any */ if (!pnm_is_space(ch)) ungetc(ch, stream); return 1; } /** * Reads a PNM header structure from a file stream and validates it. * Returns 1 on success, 0 on validation failure, * or -1 on input or matching failure. * Reading PAM ("P7") headers is not currently implemented. **/ int pnm_fget_header(pnm_struct *pnm_ptr, FILE *stream) { unsigned int format; int ch; /* clear the PNM info structure */ memset(pnm_ptr, 0, sizeof(pnm_struct)); /* read the PNM file signature */ ch = getc(stream); if (ch == EOF) /* input failure */ return -1; /* any subsequent failure is a matching failure */ if (ch != 'P') return -1; ch = getc(stream); if (ch < '1' || ch > '9') return -1; format = (unsigned int)(ch - '0'); ch = pnm_fget_char(stream); /* start using pnm_fget_char() */ if (!pnm_is_space(ch)) return -1; /* read the header */ pnm_ptr->format = format; if (format >= PNM_P1 && format <= PNM_P6) /* old-style PNM header */ { pnm_ptr->depth = (format == PNM_P3 || format == PNM_P6) ? 3 : 1; if (pnm_fscan_uint(stream, &pnm_ptr->width) != 1 || pnm_fscan_uint(stream, &pnm_ptr->height) != 1) return -1; if (format == PNM_P1 || format == PNM_P4) pnm_ptr->maxval = 1; else { if (pnm_fscan_uint(stream, &pnm_ptr->maxval) != 1) return -1; } return pnm_is_valid(pnm_ptr) ? 1 : 0; } else /* TODO: if (format == PNM_P7) ... */ return -1; } /** * Reads an array of PNM sample values from a file stream. * The values are expected to be in the format specified by pnm_ptr->format. * The array length is pnm_ptr->depth * pnm_ptr->width * num_rows. * The validity check performed on the PNM structure is only partial. * Returns 1 on success, 0 on validation failure, * or -1 on input or matching failure. * If reading is incomplete, the remaining sample values are set to 0. **/ int pnm_fget_values(const pnm_struct *pnm_ptr, unsigned int *sample_values, unsigned int num_rows, FILE *stream) { unsigned int format = pnm_ptr->format; unsigned int depth = pnm_ptr->depth; unsigned int width = pnm_ptr->width; unsigned int maxval = pnm_ptr->maxval; size_t row_length = (size_t)depth * (size_t)width; size_t num_samples = num_rows * row_length; int ch, ch8; #if PNM_UINT_BIT > 16 int ch16, ch24; #endif int mask; size_t i, j; /* read the sample values */ switch (format) { case PNM_P1: for (i = 0; i < num_samples; ++i) { do { ch = pnm_fget_char(stream); } while (pnm_is_space(ch)); if (ch != '0' && ch != '1') { ungetc(ch, stream); break; } sample_values[i] = (ch == '0') ? 1 : 0; } break; case PNM_P2: case PNM_P3: for (i = 0; i < num_samples; ++i) { if (pnm_fscan_uint(stream, &sample_values[i]) != 1) break; } break; case PNM_P4: for (i = j = 0; i < num_samples; ) { ch = getc(stream); if (ch == EOF) break; for (mask = 0x80; mask != 0; mask >>= 1) { sample_values[i++] = (ch & mask) ? 0 : 1; if (++j == row_length) { j = 0; break; } } } break; case PNM_P5: case PNM_P6: case PNM_P7: if (maxval <= 0xffU) /* 1 byte per sample */ { for (i = 0; i < num_samples; ++i) { ch = getc(stream); if (ch == EOF) break; sample_values[i] = (unsigned int)ch; } } else if (maxval <= 0xffffU) /* 2 bytes per sample */ { for (i = 0; i < num_samples; ++i) { ch8 = getc(stream); ch = getc(stream); if (ch == EOF) break; sample_values[i] = ((unsigned int)ch8 << 8) + (unsigned int)ch; } } #if PNM_UINT_BIT > 16 else if (maxval <= 0xffffffffU) /* 3 or 4 bytes per sample */ { ch24 = 0; for (i = 0; i < num_samples; ++i) { if (maxval > 0xffffffU) ch24 = getc(stream); ch16 = getc(stream); ch8 = getc(stream); ch = getc(stream); if (ch == EOF) break; sample_values[i] = ((unsigned int)ch24 << 24) + ((unsigned int)ch16 << 16) + ((unsigned int)ch8 << 8) + ((unsigned int)ch); } } #endif else /* maxval > PNM_UINT_MAX */ { errno = EINVAL; return 0; } break; default: errno = EINVAL; return 0; } /* check the result */ if (i < num_samples) { memset(sample_values + i, 0, (num_samples - i) * sizeof(unsigned int)); return -1; } return 1; } /** * Reads an array of sample bytes from a raw PNM file stream. * Multi-byte samples are stored in network order, as in the PNM stream. * The byte count is sample_size * pnm_ptr->depth * pnm_ptr->width * num_rows. * The validity check performed on the PNM structure is only partial. * Returns 1 on success, 0 on validation failure, or -1 on input failure. * If reading is incomplete, the remaining sample bytes are set to 0. **/ int pnm_fget_bytes(const pnm_struct *pnm_ptr, unsigned char *sample_bytes, size_t sample_size, unsigned int num_rows, FILE *stream) { unsigned int format = pnm_ptr->format; unsigned int depth = pnm_ptr->depth; unsigned int width = pnm_ptr->width; unsigned int maxval = pnm_ptr->maxval; size_t row_length = (size_t)depth * (size_t)width; size_t num_samples = num_rows * row_length; size_t raw_sample_size; int ch, mask; size_t i, j; /* validate the given sample size */ if (maxval <= 0xffU) raw_sample_size = 1; else if (maxval <= 0xffffU) raw_sample_size = 2; #if PNM_UINT_BIT > 16 else if (maxval <= 0xffffffU) raw_sample_size = 3; else if (maxval <= 0xffffffffU) raw_sample_size = 4; #endif else /* maxval > PNM_UINT_MAX */ raw_sample_size = !sample_size; if (raw_sample_size != sample_size) { errno = EINVAL; return 0; } /* read the raw sample bytes */ switch (format) { case PNM_P4: for (i = j = 0; i < num_samples; ) { ch = getc(stream); if (ch == EOF) break; for (mask = 0x80; mask != 0; mask >>= 1) { sample_bytes[i++] = (unsigned char)((ch & mask) ? 0 : 1); if (++j == row_length) { j = 0; break; } } } break; case PNM_P5: case PNM_P6: case PNM_P7: i = fread(sample_bytes, sample_size, num_samples, stream); break; default: errno = EINVAL; return 0; } /* check the result */ if (i < num_samples) { memset(sample_bytes + i, 0, sample_size * num_samples - i); return -1; } return 1; } optipng-0.7.7/src/pnmio/pnmio.h000066400000000000000000000062551343170417500164260ustar00rootroot00000000000000/** * pnmio.h * Simple I/O interface to the Portable Any Map (PNM) image file format. * Version 0.3, Release 2008-Jun-15. * * Copyright (C) 2002-2008 Cosmin Truta. * * This software is provided 'as-is', without any express or implied * warranty. In no event will the author(s) be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, 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 notice may not be removed or altered from any source distribution. * **/ #ifndef PNMIO_H #define PNMIO_H #include #include #include #ifdef __cplusplus extern "C" { #endif /** * PNM format codes **/ enum { PNM_P1 = 1, /* plain PBM */ PNM_P2 = 2, /* plain PGM */ PNM_P3 = 3, /* plain PPM */ PNM_P4 = 4, /* raw PBM */ PNM_P5 = 5, /* raw PGM */ PNM_P6 = 6, /* raw PPM */ PNM_P7 = 7 /* PAM (only partially implemented) */ }; /** * PNM info structure **/ typedef struct pnm_struct { unsigned int format; unsigned int depth; unsigned int width; unsigned int height; unsigned int maxval; } pnm_struct; /** * PNM input functions **/ int pnm_fget_header(pnm_struct *pnm_ptr, FILE *stream); int pnm_fget_values(const pnm_struct *pnm_ptr, unsigned int *sample_values, unsigned int num_rows, FILE *stream); int pnm_fget_bytes(const pnm_struct *pnm_ptr, unsigned char *sample_bytes, size_t sample_size, unsigned int num_rows, FILE *stream); /** * PNM output functions **/ int pnm_fput_header(const pnm_struct *pnm_ptr, FILE *stream); int pnm_fput_values(const pnm_struct *pnm_ptr, const unsigned int *sample_values, unsigned int num_rows, FILE *stream); int pnm_fput_bytes(const pnm_struct *pnm_ptr, const unsigned char *sample_bytes, size_t sample_size, unsigned int num_rows, FILE *stream); /** * PNM utility functions **/ int pnm_is_valid(const pnm_struct *pnm_ptr); size_t pnm_raw_sample_size(const pnm_struct *pnm_ptr); size_t pnm_mem_size(const pnm_struct *pnm_ptr, size_t sample_size, unsigned int num_rows); /** * PNM limits **/ #define PNM_UCHAR_BIT 8 #define PNM_UCHAR_MAX 0xffU #if UINT_MAX < 0xffffffffUL #define PNM_UINT_BIT 16 #define PNM_UINT_MAX 0xffffU #else #define PNM_UINT_BIT 32 #define PNM_UINT_MAX 0xffffffffU #endif #ifdef __cplusplus } /* extern "C" */ #endif #endif /* PNMIO_H */ optipng-0.7.7/src/pnmio/pnmout.c000066400000000000000000000161171343170417500166170ustar00rootroot00000000000000/** * pnmout.c * PNM file output. * * Copyright (C) 2002-2008 Cosmin Truta. * This file is part of the pnmio library, distributed under the zlib license. * For conditions of distribution and use, see copyright notice in pnmio.h. **/ #include #include #include #include "pnmio.h" /** * Validates a PNM header structure and writes it to a file stream. * Returns 1 on success, 0 on validation failure, or -1 on output failure. **/ int pnm_fput_header(const pnm_struct *pnm_ptr, FILE *stream) { unsigned int format = pnm_ptr->format; unsigned int depth = pnm_ptr->depth; unsigned int width = pnm_ptr->width; unsigned int height = pnm_ptr->height; unsigned int maxval = pnm_ptr->maxval; int result; /* validate the info structure */ if (!pnm_is_valid(pnm_ptr)) return 0; /* write the PNM file header */ switch (format) { case PNM_P1: case PNM_P4: result = fprintf(stream, "P%c\n%u %u\n", format + '0', width, height); break; case PNM_P2: case PNM_P3: case PNM_P5: case PNM_P6: result = fprintf(stream, "P%c\n%u %u\n%u\n", format + '0', width, height, maxval); break; case PNM_P7: result = fprintf(stream, "P7\nDEPTH %u\nWIDTH %u\nHEIGHT %u\nMAXVAL %u\nENDHDR\n", depth, width, height, maxval); break; default: errno = EINVAL; return 0; } /* check the result */ return (result > 0) ? 1 : -1; } /** * Writes an array of PNM sample values to a file stream. * The values are written in the format specified by pnm_ptr->format. * The array length is pnm_ptr->depth * pnm_ptr->width * num_rows. * The validity check performed on the PNM structure is only partial. * Returns 1 on success, 0 on validation failure, or -1 on output failure. **/ int pnm_fput_values(const pnm_struct *pnm_ptr, const unsigned int *sample_values, unsigned int num_rows, FILE *stream) { unsigned int format = pnm_ptr->format; unsigned int depth = pnm_ptr->depth; unsigned int width = pnm_ptr->width; unsigned int maxval = pnm_ptr->maxval; size_t row_length = (size_t)depth * (size_t)width; size_t num_samples = num_rows * row_length; int ch, mask; size_t i, j; /* write the sample values */ switch (format) { case PNM_P1: for (i = j = 0; i < num_samples; ++i) { if (putc(((sample_values[i] != 0) ? '0' : '1'), stream) == EOF) break; if (++j == row_length) { j = 0; if (putc('\n', stream) == EOF) break; } } break; case PNM_P2: case PNM_P3: for (i = j = 0; i < num_samples; ++i) { if (++j == row_length) j = 0; if (fprintf(stream, (j == 0) ? "%u\n" : "%u ", sample_values[i]) <= 0) break; } break; case PNM_P4: for (i = j = 0; i < num_samples; ) { ch = 0; for (mask = 0x80; mask != 0; mask >>= 1) { if (sample_values[i++] == 0) ch |= mask; if (++j == row_length) { j = 0; break; } } if (putc(ch, stream) == EOF) break; } break; case PNM_P5: case PNM_P6: case PNM_P7: if (maxval <= 0xffU) /* 1 byte per sample */ { for (i = 0; i < num_samples; ++i) { if (putc(sample_values[i] & 0xff, stream) == EOF) break; } } else if (maxval <= 0xffffU) /* 2 bytes per sample */ { for (i = 0; i < num_samples; ++i) { if (putc((sample_values[i] >> 8) & 0xff, stream) == EOF || putc((sample_values[i]) & 0xff, stream) == EOF) break; } } #if PNM_UINT_BIT > 16 else if (maxval <= 0xffffffffU) /* 3 or 4 bytes per sample */ { for (i = 0; i < num_samples; ++i) { if (maxval > 0xffffffU) if (putc((sample_values[i] >> 24) & 0xff, stream) == EOF) break; if (putc((sample_values[i] >> 16) & 0xff, stream) == EOF || putc((sample_values[i] >> 8) & 0xff, stream) == EOF || putc((sample_values[i]) & 0xff, stream) == EOF) break; } } #endif else /* maxval > PNM_UINT_MAX */ { errno = EINVAL; return 0; } break; default: errno = EINVAL; return 0; } /* check the result */ return (i == num_samples) ? 1 : -1; } /** * Writes an array of sample bytes to a raw PNM file stream. * Multi-byte samples are stored in network order, as in the PNM stream. * The byte count is sample_size * pnm_ptr->depth * pnm_ptr->width * num_rows. * The validity check performed on the PNM structure is only partial. * Returns 1 on success, 0 on validation failure, or -1 on output failure. **/ int pnm_fput_bytes(const pnm_struct *pnm_ptr, const unsigned char *sample_bytes, size_t sample_size, unsigned int num_rows, FILE *stream) { unsigned int format = pnm_ptr->format; unsigned int depth = pnm_ptr->depth; unsigned int width = pnm_ptr->width; unsigned int maxval = pnm_ptr->maxval; size_t row_length = (size_t)depth * (size_t)width; size_t num_samples = num_rows * row_length; size_t raw_sample_size; int ch, mask; size_t i, j; /* validate the given sample size */ if (maxval <= 0xffU) raw_sample_size = 1; else if (maxval <= 0xffffU) raw_sample_size = 2; #if PNM_UINT_BIT > 16 else if (maxval <= 0xffffffU) raw_sample_size = 3; else if (maxval <= 0xffffffffU) raw_sample_size = 4; #endif else /* maxval > PNM_UINT_MAX */ raw_sample_size = !sample_size; if (raw_sample_size != sample_size) { errno = EINVAL; return 0; } /* write the raw sample bytes */ switch (format) { case PNM_P4: for (i = j = 0; i < num_samples; ) { ch = 0; for (mask = 0x80; mask != 0; mask >>= 1) { if (sample_bytes[i++] == 0) ch |= mask; if (++j == row_length) { j = 0; break; } } if (putc(ch, stream) == EOF) break; } break; case PNM_P5: case PNM_P6: case PNM_P7: i = fwrite(sample_bytes, sample_size, num_samples, stream); break; default: errno = EINVAL; return 0; } /* check the result */ return (i == num_samples) ? 1 : -1; } optipng-0.7.7/src/pnmio/pnmutil.c000066400000000000000000000053401343170417500167610ustar00rootroot00000000000000/** * pnmutil.c * PNM utilities. * * Copyright (C) 2002-2008 Cosmin Truta. * This file is part of the pnmio library, distributed under the zlib license. * For conditions of distribution and use, see copyright notice in pnmio.h. **/ #include #include #include #include "pnmio.h" /** * Validates a PNM structure. * Returns 1 on success, 0 on failure. **/ int pnm_is_valid(const pnm_struct *pnm_ptr) { unsigned int format = pnm_ptr->format; unsigned int depth = pnm_ptr->depth; unsigned int width = pnm_ptr->width; unsigned int height = pnm_ptr->height; unsigned int maxval = pnm_ptr->maxval; if (depth == 0 || width == 0 || height == 0 || maxval == 0) return 0; #if PNM_UINT_MAX < UINT_MAX if (maxval > PNM_UINT_MAX) return 0; #endif switch (format) { case PNM_P1: case PNM_P4: /* PBM */ return (depth == 1 && maxval == 1) ? 1 : 0; case PNM_P2: case PNM_P5: /* PGM */ return (depth == 1) ? 1 : 0; case PNM_P3: case PNM_P6: /* PPM */ return (depth == 3) ? 1 : 0; case PNM_P7: /* PAM */ return 1; default: return 0; } } /** * Calculates the size of a raw PNM sample, i.e. the smallest number of * bytes required to store a sample value between 0 and pnm_ptr->maxval. * The validity check performed on the PNM structure is only partial. * Returns the raw sample size on success, or 0 on validation failure. **/ size_t pnm_raw_sample_size(const pnm_struct *pnm_ptr) { unsigned int maxval = pnm_ptr->maxval; if (maxval == 0) errno = EINVAL; /* fall through */ if (maxval <= 0xffU) return 1; else if (maxval <= 0xffffU) return 2; #if PNM_UINT_BIT > 16 else if (maxval <= 0xffffffU) return 3; else if (maxval <= 0xffffffffU) return 4; #endif else /* maxval > PNM_UINT_MAX */ { errno = EINVAL; return 0; } } /** * Calculates the number of bytes occupied by an array of PNM samples. * The byte count is sample_size * pnm_ptr->depth * pnm_ptr->width * num_rows. * The validity check performed on the PNM structure is only partial. * Returns the array size on success, or 0 on validation failure. **/ size_t pnm_mem_size(const pnm_struct *pnm_ptr, size_t sample_size, unsigned int num_rows) { unsigned int depth = pnm_ptr->depth; unsigned int width = pnm_ptr->width; if (sample_size == 0 || depth == 0 || width == 0) { errno = EINVAL; return 0; } if (num_rows > (size_t)(-1) / sample_size / depth / width) { errno = ERANGE; return 0; } return sample_size * depth * width * num_rows; }