From 447d3212ab1ec9e2adcfcb2ee10ffeed2bb71014 Mon Sep 17 00:00:00 2001 From: Glenn Randers-Pehrson Date: Fri, 5 Jun 2009 16:19:23 -0500 Subject: [PATCH] Imported from pngcrush-1.6.18.tar --- ChangeLog.html | 6386 ++++++++++++++++++++++++++++++++++++++++++++++++ ChangeLog.txt | 425 ---- png.c | 6 +- png.h | 21 +- pngconf.h | 2 +- pngcrush.c | 2 +- pngerror.c | 2 +- pngget.c | 23 +- pngmem.c | 2 +- pngpread.c | 2 +- pngread.c | 8 +- pngrio.c | 2 +- pngrtran.c | 2 +- pngrutil.c | 2 +- pngset.c | 2 +- pngtest.c | 1687 ------------- pngwio.c | 8 +- pngwrite.c | 2 +- pngwtran.c | 2 +- pngwutil.c | 2 +- 20 files changed, 6437 insertions(+), 2151 deletions(-) create mode 100644 ChangeLog.html delete mode 100644 ChangeLog.txt delete mode 100644 pngtest.c diff --git a/ChangeLog.html b/ChangeLog.html new file mode 100644 index 000000000..fa5e45e14 --- /dev/null +++ b/ChangeLog.html @@ -0,0 +1,6386 @@ +Pncrush ChangeLog + +
+Change log:
+
+Version 1.6.18 (built with libpng-1.2.37rc01 and zlib-1.2.3.2)
+
+Version 1.6.17 (built with libpng-1.2.36 and zlib-1.2.3.2)
+  Defined TOO_FAR == 32767 in deflate.c (again).  The definition
+    has continually been inadvertently omitted during zlib updates
+    since pngcrush version 1.6.4.
+  Revised handling of xcode files so at least we can get printout
+    of IHDR values with "pngcrush -fix -n -v xcode.png".
+  Moved ChangeLog.txt back into pngcrush.c so it does not get lost.
+  Removed single quotes from the ChangeLog.
+
+Version 1.6.16 (built with libpng-1.2.35 and zlib-1.2.3.2)
+  Added -newtimestamp and -oldtimestamp options and changed
+    default condition to timestamping the output file with
+    the current time (i.e., -newtimestamp is default)
+  If the -oldtimestamp option is used then the output file
+    has the same timestamp as the input file.
+  Added CgBI chunk detection.
+
+Version 1.6.15 (built with libpng-1.2.35 and zlib-1.2.3.2)
+  Fixes some missing typecasts on png_malloc() calls, patch from
+    an anonymous reporter to the SourceForge bug tracker.
+  Added -time_stamp option to change time stamping from default
+    condition.
+
+Version 1.6.14 (built with libpng-1.2.35 and zlib-1.2.3.2)
+  Avoids CVE-2009-0040.
+
+Version 1.6.12 (built with libpng-1.2.34 and zlib-1.2.3.2)
+
+Version 1.6.11 (built with libpng-1.2.33 and zlib-1.2.3.2)
+  Eliminated a memory leak in libpng with writing bad tEXt chunks.
+
+Version 1.6.10 (built with libpng-1.2.31 and zlib-1.2.3.2)
+  Add sTER chunk support.
+
+Version 1.6.9 (built with libpng-1.2.31 and zlib-1.2.3.2)
+  Updated cexcept.h to version 2.0.1
+  Add missing curly brackets.
+
+Version 1.6.8 (built with libpng-1.2.29 and zlib-1.2.3.2)
+  Fixed bug with handling of -z and -zi options.
+
+Version 1.6.7 (built with libpng-1.2.29 and zlib-1.2.3.2)
+  Moved PNG_UINT_CHNK and some other defines from pngcrush.h to pngcrush.c
+  Reject invalid color_type or bit_depth.
+
+Version 1.6.6 (built with libpng-1.2.29 and zlib-1.2.3.2)
+  Added dSIG support.  Pngcrush will not rewrite an image containing
+  a dSIG chunk immediately following the IHDR chunk, unless the
+  dSIG is explicitly removed with "-rem dSIG" or explicitly kept
+  with "-keep dSIG".  In the latter case the saved dSIG chunks will
+  become invalid if any changes are made to the datastream.
+
+  Fixed bug in writing unknown chunks from the end_info_ptr.
+
+Version 1.6.5 (built with libpng-1.2.29 and zlib-1.2.3.2)
+  Discontinued adding a new gAMA chunk when writing sRGB chunk.
+
+Version 1.6.4 (built with libpng-1.2.9rc1 and zlib-1.2.3)
+  Fixed bug in handling of undocumented -trns_a option (Michal Politowski).
+  Fixed bug with "nosave" handling of unknown chunks.
+
+Version 1.6.3 (built with libpng-1.2.9beta11 and zlib-1.2.3)
+
+  Fixed documentation of iTXt input (Shlomi Tal).
+  Removed #define PNG_INTERNAL and provided prototypes for some
+  internal libpng functions that are duplicated in pngcrush.c
+
+Version 1.6.2 (built with libpng-1.2.8 and zlib-1.2.3)
+
+  Fixed bug with "PNG_ROWBYTES" usage, introduced in version 1.6.0.
+  The bug could cause a crash and only affects the "nolib" builds.
+
+  Converted C++ style (// ...) comments to C style (/* ... */).
+
+  Defined TOO_FAR == 32767 in deflate.c (again).  The definition was
+  omitted from version 1.6.0 when zlib was upgraded to version 1.2.3.
+
+Version 1.6.1 (distributed as 1.6.0, built with libpng-1.2.8 and zlib-1.2.3)
+
+  Copied non-exported libpng functions from libpng into pngcrush, to make
+  pngcrush play more nicely with shared libpng.  These are not compiled
+  when a static library is being built with the bundled libpng and
+  pngcrush.h is included.
+
+Version 1.6.0-grr (built with libpng-1.2.4 and zlib-1.1.4pc or zlib-1.2.2)
+
+  Moved ChangeLog out of pngcrush.c comments and into a separate file.
+
+  Filtered pngcrush.c through "indent -kr" and "expand" for readability.
+
+  Moved 550 lines of usage/help/copyright/license/version info to separate
+  function(s) and cleaned up significantly.
+
+  Added some comments for ease of navigation and readability.
+
+  Stripped out a bunch of ancient-libpng compatibility stuff.
+
+  Defined PNG_UINT_* macros (pngcrush.h for now).
+
+  Fixed unknown-chunk handling ("-rem alla" and "-rem gifx" now work).
+
+  Created modified version of makefile that supports external zlib.
+
+  Added support for methods using Z_RLE zlib strategy (zlib 1.2.x only).
+
+  Documented -huffman option in usage screen.
+
+  Added IDAT statistics to final per-file summary.
+
+  Added utime() support to give output files same timestamps as input files.
+
+Version 1.5.10 (built with libpng-1.2.4 and zlib-1.1.4pc)
+
+  Fixed bug, introduced in 1.5.9, that caused defaults for method 0 to
+  be used instead of copying the original image, when the original was
+  already smallest.
+
+Version 1.5.9 (built with libpng-1.2.4beta3 and zlib-1.1.4pc)
+
+  Work around CPU timer wraparound at 2G microseconds.
+
+  Upgraded zlib from 1.1.3 to 1.1.4.  Pngcrush is believed not to
+  be vulnerable to the zlib-1.1.3 buffer-overflow bug.
+
+  Choose the first instance of smallest IDAT instead of the last,
+  for faster final recompression, suggested by TSamuel.
+
+Version 1.5.8 (built with libpng-1.2.1)
+
+  Added -trns_a option for entering a tRNS array.
+
+Version 1.5.7 (built with libpng-1.2.0)
+
+  Added setargv.obj to Makefile.msc to expand wildcards, e.g., *.png
+
+  Use constant string "pngcrush" instead of argv[0] when appropriate.
+
+  Only check stats for infile==outfile once per input file, or not at all
+  if "-nofilecheck" option is present or if a directory was created.
+
+  Fixed bugs with changing bit_depth of grayscale images.
+
+Version 1.5.6 (built with libpng-1.0.12)
+
+  Eliminated extra "Removed the cHNK chunk" messages generated by version
+  1.5.5 when "-rem alla" or "-rem allb" is used.
+
+  All unknown chunks including safe-to-copy chunks are now removed in
+  response to the "-rem alla" or "-rem allb" options.
+
+  Issue a warning if the user tries "-cc" option when it is not supported.
+
+Version 1.5.5 (built with libpng-1.0.12)
+
+  Reset reduce_to_gray and it_is_opaque flags prior to processing each
+  image.
+
+  Enable removal of safe-to-copy chunks that are being handled as unknown
+  e.g., "-rem time".
+
+Version 1.5.4 (built with libpng-1.0.11)
+
+  Added 262 to the length of uncompressed data when calculating
+  required_window_size, to account for zlib/deflate implementation.
+
+  Added "-bit_depth n" to the help screen.
+
+  Call png_set_packing() when increasing bit_depth to 2 or 4.
+
+  Added warning about not overwriting an existing tRNS chunk.
+
+  Reduced the memory usage
+
+  Write 500K IDAT chunks even when system libpng is being used.
+
+  Ignore all-zero cHRM chunks, with a warning.
+
+Version 1.5.3 (built with libpng-1.0.9beta5)
+
+  Added "-loco" option (writes MNG files with filter_method 64)
+
+  "-dir" and "-ext" options are no longer mutually exclusive, e.g.:
+  pngcrush -loco -dir Crushed -ext .mng *.png
+
+Version 1.5.2 (built with libpng-1.0.9beta1)
+
+  Added "-iccp" option.
+
+  Increased the zlib memory level, which improves compression (typically
+  about 1.3 percent for photos) at the expense of increased memory usage.
+
+  Enabled the "-max max_idat_size" option, even when max_idat_size
+  exceeds the default 1/2 megabyte size.
+
+  Added missing "png_ptr" argument to png_error() call
+
+  Added "-loco" option, to enable the LOCO color transformation
+  (R->R-G, G, B->B-G) while writing a MNG with filter_method 64. Undo
+  the transformation and write the regular PNG filter_method (0) if the
+  MNG filter_method 64 is detected.
+
+  Revised the "-help" output slightly and improved the "-version" output.
+
+  The "-already[_crushed]" option is now ignored if the "-force" option
+  is present or if chunks are being added, deleted, or modified.
+
+  Improved "things_have_changed" behavior (now, when set in a particular
+  file, it is not set for all remaining files)
+
+Version 1.5.1 (built with libpng-1.0.8)
+
+  Disabled color counting by default and made it controllable with new
+  -cc and -no_cc commandline arguments.
+
+  Added some #ifdef PNGCRUSH_COUNT_COLORS around code that needs it.
+
+  Revised count_colors() attempting to avoid stack corruption that has
+  been observed on RedHat 6.2
+
+  Added the word "irrevocably" to the license and changed "without fee"
+  to "without payment of any fee".
+
+Version 1.5.0 (built with libpng-1.0.8)
+
+  After encountering an image with a bad Photoshop iCCP chunk, pngcrush
+  1.4.5 through 1.4.8 write sRGB and gAMA=45455 chunks in all
+  remaining PNG files on the command line.  This has been fixed so the
+  correction is only applied to the particular bad input file.
+
+Version 1.4.8 (built with libpng-1.0.8rc1)
+
+  Detect and remove all-opaque alpha channel.
+  Detect and reduce all-gray truecolor images to grayscale.
+
+Version 1.4.7 (built with libpng-1.0.8rc1)
+
+  Restored the "-ext" option that was inadvertently overridden with
+  a new "-exit" option in version 1.4.6 ("-exit" is used to force an
+  "exit" instead of a "return" from the main program).
+
+Version 1.4.6 (built with libpng-1.0.8rc1)
+
+  Fixed bug in color-counting of noninterlaced images.
+
+  Added capability of processing multiple rows at a time (disabled by
+  default because it turns out to be no faster).
+
+  Replaced "return" statements in main() with "exit" statements.
+  Force exit instead of return with "-exit" argument.
+
+  Added the UCITA disclaimers to the help output.
+
+Version 1.4.5 (built with libpng-1.0.7rc2 and cexcept-1.0.0)
+
+  Added color-counting and palette-building capability (enable by
+  defining PNGCRUSH_COUNT_COLORS).  In a future version, this will
+  give pngcrush the ability to reduce RGBA images to indexed-color
+  or grayscale when fewer than 257 RGBA combinations are present,
+  and no color is present that requires 16-bit precision.  For now,
+  it only reports the frequencies.
+  
+  Added "-fix" option, for fixing bad CRCs and other correctable
+  conditions.
+
+  Write sBIT.alpha=1 when adding an opaque alpha channel and sBIT
+  is present.
+
+  Identify the erroneous 2615-byte sRGB monitor profile being written
+  by Photoshop 5.5, which causes many apps to crash, and replace it with
+  an sRGB chunk.
+
+  Added a check for input and output on different devices before rejecting
+  the output file as being the same as the input file based on inode.
+
+  Added some UCITA language to the disclaimer.
+
+Version 1.4.4 (built with libpng-1.0.6i and cexcept-0.6.3)
+
+  Can be built on RISC OS platforms, thanks to Darren Salt.
+
+Version 1.4.3 (built with libpng-1.0.6h and cexcept-0.6.3)
+
+  Reduced scope of Try/Catch blocks to avoid nesting them, and
+  removed returns from within the Try blocks, where they are not
+  allowed.
+
+  Removed direct access to the png structure when possible, and isolated
+  the remaining direct accesses to the png structure into new
+  png_get_compression_buffer_size(), png_set_compression_buffer_size(),
+  and png_set_unknown_chunk_location() functions that were installed
+  in libpng version 1.0.6g.
+
+Version 1.4.2 (built with libpng-1.0.6f and cexcept-0.6.0)
+
+  Removes extra IDAT chunks (such as found in some POV-ray PNGs) with
+  a warning instead of bailing out (this feature requires libpng-1.0.6f
+  or later, compiled with "#define PNG_ABORT()").
+
+  Removed old setjmp interface entirely.
+
+Version 1.4.1 (built with libpng-1.0.6e and cexcept-0.6.0)
+
+  Uses cexcept.h for error handling instead of libpngs built-in
+  setjmp/longjmp mechanism.  See http://cexcept.sf.net/
+
+  Pngcrush.c will now run when compiled with old versions of libpng back
+  to version 0.96, although some features will not be available.
+
+Version 1.4.0 (built with libpng-1.0.6 + libpng-1.0.6-patch-a)
+
+Version 1.3.6 (built with libpng-1.0.5v)
+
+  RGB to Grayscale conversion is more accurate (15-bit instead of 8-bit)
+  and now uses only integer arithmetic.
+
+  "#ifdefed" out PNG_READ_DITHER
+
+  Changed "Compressed" to "Uncompressed" in help for -itxt.
+
+  Stifled some compiler warnings
+
+Version 1.3.5 (built with libpng-1.0.5s)
+
+  Add test on stat_buf.st_size to verify fpin==fpout, because stat in
+  MSVC++6.0 standard version returns stat_buf.st_ino=0 for all files.
+
+  Revised pngcrush.h to make it easier to control PNG_ZBUF_SIZE and
+  PNG_NO_FLOATING_POINT_SUPPORTED from a makefile.
+
+  Restored ability to enter "replace_gamma" value as a float even when
+  floating point arithmetic is not enabled.
+
+  Enabled removing tEXt, zTXt, or iTXt chunks by chunk type, i.e.,
+  "-rem tEXt" only removes tEXt chunks, while "-rem text" removes all
+  three types of text chunk.
+
+  Removed definition of TOO_FAR from pngcrush.h
+
+  Uses new libpng error handler; if a file has errors, pngcrush now will
+  continue on and compress the remaining files instead of bailing out.
+
+Version 1.3.4 (built with libpng-1.0.5m)
+
+  Do not allow pngcrush to overwrite the input file.
+
+Version 1.3.3 (built with libpng-1.0.5m)
+
+  Restored ability to enter gamma as a float even when floating point
+  arithmetic is not enabled.
+
+Version 1.3.2 (built with libpng-1.0.5k)
+  
+  Renamed "dirname" to "directory_name" to avoid conflict with "dirname"
+  that appears in string.h on some platforms.
+
+  Fixed "PNG_NO_FLOAING_POINT" typo in pngcrush.h
+
+  "#ifdefed" out parts of the help screen for options that are unsupported.
+
+Version 1.3.1 (built with libpng-1.0.5k): Eliminated some spurious warnings
+  that were being issued by libpng-1.0.5j.  Added  -itxt, -ztxt, and
+  -zitxt descriptions to the help screen.
+
+  Dropped explicit support for pCAL, hIST, sCAL, sPLT, iCCP, tIME, and
+  cHRM chunks and handle them as unknown but safe-to-copy instead, using
+  new png_handle_as_unknown function available in libpng-1.0.5k.
+
+Version 1.3.0 (built with libpng-1.0.5j): Added support for handling
+  unknown chunks.
+
+  pngcrush is now fixed-point only, unless PNG_NO_FLOATING_POINT_SUPPORTED
+  is undefined in pngcrush.h.
+
+  Added support for the iCCP, iTXt, sCAL, and sPLT chunks, which
+  are now supported by libpng (since libpng-1.0.5j).  None of these have
+  been adequately tested.
+
+  "#ifdefed" out more unused code (weighted filters and progressive read;
+  this saves about 15k in the size of the executable).
+
+  Moved the special definitions from pngconf.h into a new pngcrush.h
+
+  Disallow 256-byte compression window size when writing, to work around
+  an apparent zlib bug.  Either deflate was producing incorrect results in a
+  21x21 4-bit image or inflate was decoding it incorrectly; the uncompressed
+  stream is 252 bytes, which is uncomfortably close to the resulting
+  256-byte compression  window.  This workaround can be removed when zlib
+  is fixed.
+
+  The "-m method" can be used any of the 124 methods, without having to
+  specify the filter, level, and strategy, instead of just the first 10.
+
+Version 1.2.1 (built with libpng-1.0.5f): Fixed -srgb parameter so it
+  really does take an argument, and so it continues to use "0" if an
+  integer does not follow the -srgb.
+
+  Added "-plte_len n" argument for truncating the PLTE.  Be sure not to
+  truncate it to less than the greatest index actually appearing in IDAT.
+
+Version 1.2.0: Removed registration requirement.  Added open source
+  license.  Redefined TOO_FAR=32k in deflate.c.
+
+Changes prior to going "open source":
+
+Version 1.1.8: built with libpng-1.0.5a.  Runs OK with pngvcrd.c.
+
+Version 1.1.7: added ability to add tEXt/zTXt chunks.  Fixed bug with
+closing a file that was not opened when using "pngcrush -n".  Fixed
+bug with tEXt/zTXt chunks after IDAT not being copied.
+Added alpha to the displayed palette table.  Rebuilt with libpng-1.0.5.
+
+Version 1.1.6: fixed bug with one file left open after each image is
+processed
+
+Version 1.1.5: Shorten or remove tRNS chunks that are all opaque or have
+opaque entries at the end.  Added timing report.
+
+Version 1.1.4: added ability to restrict brute_force to one or more filter
+  types, compression levels, or compression strategies.
+
+#endif /* end of changelog */
+
+#include "png.h"
+
+/* internal libpng macros */
+
+
+#ifdef PNG_LIBPNG_VER
+#define PNGCRUSH_LIBPNG_VER PNG_LIBPNG_VER
+#else
+/* 
+ * This must agree with PNG_LIBPNG_VER; you have to define it manually
+ * here if you are using libpng-1.0.6h or earlier
+ */
+#define PNGCRUSH_LIBPNG_VER 10007
+#endif
+
+/* Changed in version 0.99 */
+#if PNGCRUSH_LIBPNG_VER < 99
+#undef PNG_CONST
+#ifndef PNG_NO_CONST
+#  define PNG_CONST const
+#else
+#  define PNG_CONST
+#endif
+#endif
+
+#define PNG_IDAT const png_byte png_IDAT[5] = { 73,  68,  65,  84, '\0'}
+#define PNG_IHDR const png_byte png_IHDR[5] = { 73,  72,  68,  82, '\0'}
+#define PNG_dSIG const png_byte png_dSIG[5] = {100,  83,  73,  71, '\0'}
+#define PNG_iCCP const png_byte png_iCCP[5] = {105,  67,  67,  80, '\0'}
+#define PNG_IEND const png_byte png_IEND[5] = { 73,  69,  78,  68, '\0'}
+
+/* GRR 20050220:  added these, which apparently aren't defined anywhere else */
+#ifndef PNG_UINT_IHDR
+#  define PNG_UINT_IHDR (((png_uint_32)  73<<24) | \
+                         ((png_uint_32)  72<<16) | \
+                         ((png_uint_32)  68<< 8) | \
+                         ((png_uint_32)  82    ))
+#endif
+
+#ifndef PNG_UINT_IDAT
+#  define PNG_UINT_IDAT (((png_uint_32)  73<<24) | \
+                         ((png_uint_32)  68<<16) | \
+                         ((png_uint_32)  65<< 8) | \
+                         ((png_uint_32)  84    ))
+#endif
+
+#ifndef PNG_UINT_IEND
+#  define PNG_UINT_IEND (((png_uint_32)  73<<24) | \
+                         ((png_uint_32)  69<<16) | \
+                         ((png_uint_32)  78<< 8) | \
+                         ((png_uint_32)  68    ))
+#endif
+
+#ifndef PNG_UINT_PLTE
+#  define PNG_UINT_PLTE (((png_uint_32)  80<<24) | \
+                         ((png_uint_32)  76<<16) | \
+                         ((png_uint_32)  84<< 8) | \
+                         ((png_uint_32)  69    ))
+#endif
+
+#ifndef PNG_UINT_bKGD
+#  define PNG_UINT_bKGD (((png_uint_32)  98<<24) | \
+                         ((png_uint_32)  75<<16) | \
+                         ((png_uint_32)  71<< 8) | \
+                         ((png_uint_32)  68    ))
+#endif
+
+/* glennrp added CgBI at pngcrush-1.6.16 */
+#ifndef PNG_UINT_CgBI
+#  define PNG_UINT_CgBI (((png_uint_32)  67<<24) | \
+                         ((png_uint_32) 103<<16) | \
+                         ((png_uint_32)  66<< 8) | \
+                         ((png_uint_32)  73    ))
+#endif
+
+#ifndef PNG_UINT_cHRM
+#  define PNG_UINT_cHRM (((png_uint_32)  99<<24) | \
+                         ((png_uint_32)  72<<16) | \
+                         ((png_uint_32)  82<< 8) | \
+                         ((png_uint_32)  77    ))
+#endif
+
+#ifndef PNG_UINT_dSIG
+#  define PNG_UINT_dSIG (((png_uint_32) 100<<24) | \
+                         ((png_uint_32)  83<<16) | \
+                         ((png_uint_32)  73<< 8) | \
+                         ((png_uint_32)  71    ))
+#endif
+
+#ifndef PNG_UINT_gAMA
+#  define PNG_UINT_gAMA (((png_uint_32) 103<<24) | \
+                         ((png_uint_32)  65<<16) | \
+                         ((png_uint_32)  77<< 8) | \
+                         ((png_uint_32)  65    ))
+#endif
+
+#ifndef PNG_UINT_hIST
+#  define PNG_UINT_hIST (((png_uint_32) 104<<24) | \
+                         ((png_uint_32)  73<<16) | \
+                         ((png_uint_32)  83<< 8) | \
+                         ((png_uint_32)  84    ))
+#endif
+
+#ifndef PNG_UINT_iCCP
+#  define PNG_UINT_iCCP (((png_uint_32) 105<<24) | \
+                         ((png_uint_32)  67<<16) | \
+                         ((png_uint_32)  67<< 8) | \
+                         ((png_uint_32)  80    ))
+#endif
+
+#ifndef PNG_UINT_iTXt
+#  define PNG_UINT_iTXt (((png_uint_32) 105<<24) | \
+                         ((png_uint_32)  84<<16) | \
+                         ((png_uint_32)  88<< 8) | \
+                         ((png_uint_32) 116    ))
+#endif
+
+#ifndef PNG_UINT_oFFs
+#  define PNG_UINT_oFFs (((png_uint_32) 111<<24) | \
+                         ((png_uint_32)  70<<16) | \
+                         ((png_uint_32)  70<< 8) | \
+                         ((png_uint_32) 115    ))
+#endif
+
+#ifndef PNG_UINT_pCAL
+#  define PNG_UINT_pCAL (((png_uint_32) 112<<24) | \
+                         ((png_uint_32)  67<<16) | \
+                         ((png_uint_32)  65<< 8) | \
+                         ((png_uint_32)  76    ))
+#endif
+
+#ifndef PNG_UINT_pHYs
+#  define PNG_UINT_pHYs (((png_uint_32) 112<<24) | \
+                         ((png_uint_32)  72<<16) | \
+                         ((png_uint_32)  89<< 8) | \
+                         ((png_uint_32) 115    ))
+#endif
+
+#ifndef PNG_UINT_sBIT
+#  define PNG_UINT_sBIT (((png_uint_32) 115<<24) | \
+                         ((png_uint_32)  66<<16) | \
+                         ((png_uint_32)  73<< 8) | \
+                         ((png_uint_32)  84    ))
+#endif
+
+#ifndef PNG_UINT_sCAL
+#  define PNG_UINT_sCAL (((png_uint_32) 115<<24) | \
+                         ((png_uint_32)  67<<16) | \
+                         ((png_uint_32)  65<< 8) | \
+                         ((png_uint_32)  76    ))
+#endif
+
+#ifndef PNG_UINT_sPLT
+#  define PNG_UINT_sPLT (((png_uint_32) 115<<24) | \
+                         ((png_uint_32)  80<<16) | \
+                         ((png_uint_32)  76<< 8) | \
+                         ((png_uint_32)  84    ))
+#endif
+
+#ifndef PNG_UINT_sTER
+#  define PNG_UINT_sTER (((png_uint_32) 115<<24) | \
+                         ((png_uint_32)  84<<16) | \
+                         ((png_uint_32)  69<< 8) | \
+                         ((png_uint_32)  82    ))
+#endif
+
+#ifndef PNG_UINT_sRGB
+#  define PNG_UINT_sRGB (((png_uint_32) 115<<24) | \
+                         ((png_uint_32)  82<<16) | \
+                         ((png_uint_32)  71<< 8) | \
+                         ((png_uint_32)  66    ))
+#endif
+
+#ifndef PNG_UINT_tEXt
+#  define PNG_UINT_tEXt (((png_uint_32) 116<<24) | \
+                         ((png_uint_32)  69<<16) | \
+                         ((png_uint_32)  88<< 8) | \
+                         ((png_uint_32) 116    ))
+#endif
+
+#ifndef PNG_UINT_tIME
+#  define PNG_UINT_tIME (((png_uint_32) 116<<24) | \
+                         ((png_uint_32)  73<<16) | \
+                         ((png_uint_32)  77<< 8) | \
+                         ((png_uint_32)  69    ))
+#endif
+
+#ifndef PNG_UINT_tRNS
+#  define PNG_UINT_tRNS (((png_uint_32) 116<<24) | \
+                         ((png_uint_32)  82<<16) | \
+                         ((png_uint_32)  78<< 8) | \
+                         ((png_uint_32)  83    ))
+#endif
+
+#ifndef PNG_UINT_zTXt
+#  define PNG_UINT_zTXt (((png_uint_32) 122<<24) | \
+                         ((png_uint_32)  84<<16) | \
+                         ((png_uint_32)  88<< 8) | \
+                         ((png_uint_32) 116    ))
+#endif
+
+#define PNG_FLAG_CRC_ANCILLARY_USE        0x0100
+#define PNG_FLAG_CRC_ANCILLARY_NOWARN     0x0200
+#define PNG_FLAG_CRC_CRITICAL_USE         0x0400
+#define PNG_FLAG_CRC_CRITICAL_IGNORE      0x0800
+#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \
+                                     PNG_FLAG_CRC_ANCILLARY_NOWARN)
+#define PNG_PACK               0x0004
+#define PNG_DITHER             0x0040
+#define PNG_BACKGROUND         0x0080
+#define PNG_16_TO_8            0x0400
+#define PNG_RGBA               0x0800
+#define PNG_EXPAND             0x1000
+#define PNG_GAMMA              0x2000
+#define PNG_GRAY_TO_RGB        0x4000
+#define PNG_FILLER             0x8000L
+#define PNG_USER_TRANSFORM   0x100000L
+#define PNG_RGB_TO_GRAY      0x600000L  /* two bits, RGB_TO_GRAY_ERR|WARN */
+
+/*
+ * We don't need some of the extra libpng transformations
+ * so they are ifdef'ed out in pngcrush.h, which is included by
+ * pngcrush's local copy of libpng's pngconf.h which is included
+ * by png.h
+ *
+ */
+
+/* defined so I can write to a file on gui/windowing platforms */
+/*  #define STDERR stderr  */
+#define STDERR stdout /* for DOS */
+
+#ifndef PNGCRUSH_LIBPNG_VER
+#  define PNGCRUSH_LIBPNG_VER PNG_LIBPNG_VER
+#endif
+
+#ifdef PNG_MNG_FEATURES_SUPPORTED
+# define PNGCRUSH_LOCO
+#endif
+
+#ifndef PNG_UINT_31_MAX
+#define PNG_UINT_31_MAX ((png_uint_32)0x7fffffffL)
+#endif
+
+/* These macros were renamed in libpng-1.2.6 */
+#ifndef PNG_HANDLE_CHUNK_ALWAYS
+#define PNG_HANDLE_CHUNK_ALWAYS  HANDLE_CHUNK_ALWAYS
+#define PNG_HANDLE_CHUNK_NEVER   HANDLE_CHUNK_NEVER
+#define PNG_HANDLE_CHUNK_IF_SAFE HANDLE_CHUNK_IF_SAFE
+#endif
+
+#if defined(__DJGPP__)
+#  if ((__DJGPP__ == 2) && (__DJGPP_MINOR__ == 0))
+#    include      /* for _USE_LFN, djgpp 2.0 only */
+#  endif
+#  define SLASH "\\"
+#  define DOT "."
+#else
+#  ifdef __riscos
+#    define SLASH "."
+#    define DOT "/"
+#  else
+#    define SLASH "/"
+#    define DOT "."
+#  endif
+#endif
+
+#ifndef GAS_VERSION
+#  define GAS_VERSION "2.9.5(?)"  /* used only in help/usage screen */
+#endif
+
+#if !defined(__TURBOC__) && !defined(_MSC_VER) && !defined(_MBCS) && \
+    !defined(__riscos)
+#  include 
+#endif
+
+#ifndef __riscos
+#  include 
+#  include 
+#  include 
+#endif
+
+#include 
+#include 
+#include 
+#include 
+
+#if defined(_MBCS) || defined(WIN32) || defined(__WIN32__)
+#  include 
+#endif
+
+#define DEFAULT_MODE     0
+#define DIRECTORY_MODE   1
+#define EXTENSION_MODE   2
+#define DIREX_MODE       3
+#define FOPEN(file, how) fopen(file, how)
+#define FCLOSE(file)     {fclose(file); file=NULL;--number_of_open_files;};
+
+#define P0 if(first_trial && verbose > 0)printf
+#define P1 if(verbose > 1)printf
+#define P2 if(verbose > 2)printf
+
+#define STRNGIFY_STAGE1(x) #x
+#define STRNGIFY(x) STRNGIFY_STAGE1(x)
+
+#define STR_BUF_SIZE      256
+#define MAX_IDAT_SIZE     524288L
+#define MAX_METHODS       200
+#define MAX_METHODSP1     (MAX_METHODS+1)
+#define DEFAULT_METHODS   10
+#define FAKE_PAUSE_STRING "P"
+
+#ifdef Z_RLE
+#  define NUM_STRATEGIES  4
+#else
+#  define NUM_STRATEGIES  3
+#endif
+
+#ifdef __TURBOC__
+#  include 
+#endif
+
+#ifndef CLOCKS_PER_SEC
+#  define CLOCKS_PER_SEC 1000
+#endif
+
+#ifdef __STDC__
+#  define TIME_T clock_t
+#else
+#  if CLOCKS_PER_SEC <= 100
+#    define TIME_T long
+#  else
+#    define TIME_T float
+#  endif
+#endif
+
+struct options_help {
+    int verbosity;          /* if verbose >= this value, then print line */
+    const char *textline;   /* static string with newline chopped off */
+};
+
+/* input and output filenames */
+static PNG_CONST char *progname;
+static PNG_CONST char *inname = "pngtest" DOT "png";
+static PNG_CONST char *outname = "pngout" DOT "png";
+static PNG_CONST char *mngname = "mngout" DOT "mng";
+static PNG_CONST char *directory_name = "pngcrush" DOT "bak";
+static PNG_CONST char *extension = "_C" DOT "png";
+
+static png_uint_32 width, height;
+static png_uint_32 measured_idat_length;
+static int found_gAMA = 0;
+static int found_cHRM = 0;
+static int found_CgBI = 0;
+static int found_any_chunk = 0;
+static int image_is_immutable = 0;
+static int pngcrush_must_exit = 0;
+static int all_chunks_are_safe = 0;
+static int number_of_open_files;
+static int do_pplt = 0;
+#ifdef PNGCRUSH_MULTIPLE_ROWS
+static png_uint_32 max_rows_at_a_time = 1;
+static png_uint_32 rows_at_a_time;
+#endif
+char pplt_string[1024];
+char *ip, *op, *dot;
+char in_string[STR_BUF_SIZE];
+char prog_string[STR_BUF_SIZE];
+char out_string[STR_BUF_SIZE];
+char in_extension[STR_BUF_SIZE];
+static int text_inputs = 0;
+int text_where[10];           /* 0: no text; 1: before PLTE; 2: after PLTE */
+int text_compression[10];     /* -1: uncompressed tEXt; 0: compressed zTXt
+                                  1: uncompressed iTXt; 2: compressed iTXt */
+char text_text[20480];        /* It would be nice to png_malloc this, but we
+                               * don't have a png_ptr yet when we need it. */
+char text_keyword[800];
+
+/* PNG_iTXt_SUPPORTED */
+char text_lang[800];
+char text_lang_key[800];
+
+/* PNG_iCCP_SUPPORTED */
+int iccp_length = 0;
+char *iccp_text;
+char *iccp_file;
+char iccp_name[80];
+
+int best;
+
+char buffer[256];
+
+/* Set up the "cexcept" Try/Throw/Catch exception handler. */
+#include "cexcept.h"
+define_exception_type(const char *);
+extern struct exception_context the_exception_context[1];
+struct exception_context the_exception_context[1];
+png_const_charp msg;
+
+static png_uint_32 total_input_length = 0;
+static png_uint_32 total_output_length = 0;
+static int pngcrush_mode = DEFAULT_MODE;
+static int resolution = 0;
+static int remove_chunks = 0;
+static int output_color_type;
+static int output_bit_depth;
+static int force_output_color_type = 8;
+static int force_output_bit_depth = 0;
+static int input_color_type;
+static int input_bit_depth;
+static int trial;
+static int first_trial = 0;
+static int verbose = 1;
+static int fix = 0;
+static int things_have_changed = 0;
+static int global_things_have_changed = 0;
+static int default_compression_window = 15;
+static int force_compression_window = 0;
+static int compression_mem_level = 9;
+static int final_method = 0;
+static int brute_force = 0;
+static int brute_force_level = 0;
+static int brute_force_filter = 0;
+static int brute_force_strategy = 0;
+static int brute_force_levels[10] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
+static int brute_force_filters[6] = { 1, 1, 1, 1, 1, 1 };
+#ifdef Z_RLE
+static int brute_force_strategies[NUM_STRATEGIES] = { 1, 1, 1, 1 };
+#else
+static int brute_force_strategies[NUM_STRATEGIES] = { 1, 1, 1 };
+#endif
+static int method = 10;
+static int pauses = 0;
+static int nosave = 0;
+static int nofilecheck = 0;
+#ifdef PNGCRUSH_LOCO
+static int new_mng = 0;
+#endif
+static png_bytep row_buf;
+#ifdef PNGCRUSH_MULTIPLE_ROWS
+static png_bytepp row_pointers;
+#endif
+static int z_strategy;
+static int best_of_three;
+static int methods_specified = 0;
+static int intent = -1;
+static int ster_mode = -1;
+static int new_time_stamp = 1;
+static int plte_len = -1;
+#ifdef PNG_FIXED_POINT_SUPPORTED
+static int specified_gamma = 0;
+static int image_specified_gamma = 0;
+static int force_specified_gamma = 0;
+#else
+static double specified_gamma = 0.0;
+static double image_specified_gamma = 0;
+static double force_specified_gamma = 0.0;
+#endif
+static int double_gamma = 0;
+
+static int names;
+
+static int have_trns = 0;
+static png_uint_16 trns_index = 0;
+static png_uint_16 trns_red = 0;
+static png_uint_16 trns_green = 0;
+static png_uint_16 trns_blue = 0;
+static png_uint_16 trns_gray = 0;
+
+static png_byte trns_array[256];
+static png_byte trans_in[256];
+static png_uint_16 num_trans_in;
+
+static int have_bkgd = 0;
+static png_uint_16 bkgd_red = 0;
+static png_uint_16 bkgd_green = 0;
+static png_uint_16 bkgd_blue = 0;
+
+static png_colorp palette;
+static int num_palette;
+
+#ifdef REORDER_PALETTE
+static png_byte palette_reorder[256];
+#endif
+
+static png_structp read_ptr, write_ptr, mng_ptr;
+static png_infop read_info_ptr, write_info_ptr;
+static png_infop end_info_ptr;
+static png_infop write_end_info_ptr;
+static FILE *fpin, *fpout, *mng_out;
+png_uint_32 measure_idats(FILE * fpin);
+#ifdef PNGCRUSH_LOCO
+static int do_loco = 0;
+static int input_format = 0;    /* 0: PNG  1: MNG */
+static int output_format = 0;
+#endif
+static int do_color_count;
+static int reduction_ok = 0;
+#ifdef PNGCRUSH_COUNT_COLORS
+int count_colors(FILE * fpin);
+static int num_rgba, reduce_to_gray, it_is_opaque;
+#endif
+png_uint_32 png_measure_idat(png_structp png_ptr);
+
+static png_uint_32 idat_length[MAX_METHODSP1];
+static int filter_type, zlib_level;
+static png_bytep png_row_filters = NULL;
+static float t_start, t_stop, t_decode, t_encode, t_misc;
+
+static png_uint_32 max_idat_size = MAX_IDAT_SIZE; /* increases the IDAT size */
+static png_uint_32 crushed_idat_size = 0x3ffffffL;
+static int already_crushed = 0;
+int ia;
+
+
+/* prototypes */
+static void png_cexcept_error(png_structp png_ptr, png_const_charp msg);
+
+void PNGAPI png_default_read_data(png_structp png_ptr, png_bytep data,
+  png_size_t length);
+
+void png_read_transform_info(png_structp png_ptr, png_infop info_ptr);
+
+void PNGAPI png_default_write_data(png_structp png_ptr, png_bytep data,
+  png_size_t length);
+
+void png_reset_crc(png_structp png_ptr);
+void png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length);
+void png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length);
+int png_crc_error(png_structp png_ptr);
+int png_crc_finish(png_structp png_ptr, png_uint_32 skip);
+
+void png_save_uint_32(png_bytep buf, png_uint_32 i);
+
+#ifdef PNG_USER_MEM_SUPPORTED
+png_voidp png_debug_malloc(png_structp png_ptr, png_uint_32 size);
+void png_debug_free(png_structp png_ptr, png_voidp ptr);
+#endif
+
+void png_crush_pause(void);
+
+#ifdef __riscos
+static int fileexists(const char *name)
+static int filesize(const char *name)
+static int mkdir(const char *name, int ignored)
+static void setfiletype(const char *name)
+#endif
+
+int keep_unknown_chunk(png_const_charp name, char *argv[]);
+int keep_chunk(png_const_charp name, char *argv[]);
+void show_result(void);
+png_uint_32 measure_idats(FILE * fpin);
+png_uint_32 png_measure_idat(png_structp png_ptr);
+
+#ifdef PNGCRUSH_COUNT_COLORS
+int count_colors(FILE * fpin);
+#endif
+void print_version_info(void);
+void print_usage(int retval);
+
+
+#if (!defined(PNGCRUSH_H))
+/*
+ * ============================================================
+ * We aren't using the bundled libpng functions, so we must
+ * reproduce the libpng routines that aren't exported by libpng
+ * ============================================================
+ */
+
+#ifndef PNG_READ_BIG_ENDIAN_SUPPORTED
+/* Grab an unsigned 32-bit integer from a buffer in big-endian format. */
+png_uint_32 /* PRIVATE */
+png_get_uint_32(png_bytep buf)
+{
+   png_uint_32 i = ((png_uint_32)(*buf) << 24) +
+      ((png_uint_32)(*(buf + 1)) << 16) +
+      ((png_uint_32)(*(buf + 2)) << 8) +
+      (png_uint_32)(*(buf + 3));
+
+   return (i);
+}
+#else
+#  define png_get_uint_32(buf) ( *((png_uint_32p) (buf)))
+#endif
+png_uint_32 /* PRIVATE */
+png_get_uint_31(png_structp png_ptr, png_bytep buf)
+{
+   png_uint_32 i = png_get_uint_32(buf);
+   if (i > PNG_UINT_31_MAX)
+     png_error(png_ptr, "PNG unsigned integer out of range.\n");
+   return (i);
+}
+void /* PRIVATE */
+png_save_uint_32(png_bytep buf, png_uint_32 i)
+{
+   buf[0] = (png_byte)((i >> 24) & 0xff);
+   buf[1] = (png_byte)((i >> 16) & 0xff);
+   buf[2] = (png_byte)((i >> 8) & 0xff);
+   buf[3] = (png_byte)(i & 0xff);
+}
+
+/*
+ * Reset the CRC variable to 32 bits of 1's.  Care must be taken
+ * in case CRC is > 32 bits to leave the top bits 0.
+ */
+void /* PRIVATE */
+png_reset_crc(png_structp png_ptr)
+{
+   png_ptr->crc = crc32(0, Z_NULL, 0);
+}
+/*
+ * Calculate the CRC over a section of data.  We can only pass as
+ * much data to this routine as the largest single buffer size.  We
+ * also check that this data will actually be used before going to the
+ * trouble of calculating it.
+ */
+void /* PRIVATE */
+png_calculate_crc(png_structp png_ptr, png_bytep ptr, png_size_t length)
+{
+   int need_crc = 1;
+
+   if (png_ptr->chunk_name[0] & 0x20)                     /* ancillary */
+   {
+      if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
+          (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
+         need_crc = 0;
+   }
+   else                                                    /* critical */
+   {
+      if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
+         need_crc = 0;
+   }
+
+   if (need_crc)
+      png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length);
+}
+
+/* Read data, and (optionally) run it through the CRC. */
+void /* PRIVATE */
+png_crc_read(png_structp png_ptr, png_bytep buf, png_size_t length)
+{
+   png_default_read_data(png_ptr, buf, length);
+   png_calculate_crc(png_ptr, buf, length);
+}
+
+/* Compare the CRC stored in the PNG file with that calculated by libpng from
+   the data it has read thus far. */
+int /* PRIVATE */
+png_crc_error(png_structp png_ptr)
+{
+   png_byte crc_bytes[4];
+   png_uint_32 crc;
+   int need_crc = 1;
+
+   if (png_ptr->chunk_name[0] & 0x20)                     /* ancillary */
+   {
+      if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) ==
+          (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN))
+         need_crc = 0;
+   }
+   else                                                    /* critical */
+   {
+      if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE)
+         need_crc = 0;
+   }
+
+   png_default_read_data(png_ptr, crc_bytes, 4);
+
+   if (need_crc)
+   {
+      crc = png_get_uint_32(crc_bytes);
+      return ((int)(crc != png_ptr->crc));
+   }
+   else
+      return (0);
+}
+
+/*
+ * Optionally skip data and then check the CRC.  Depending on whether we
+ * are reading a ancillary or critical chunk, and how the program has set
+ * things up, we may calculate the CRC on the data and print a message.
+ * Returns '1' if there was a CRC error, '0' otherwise.
+ */
+int /* PRIVATE */
+png_crc_finish(png_structp png_ptr, png_uint_32 skip)
+{
+   png_size_t i;
+   png_size_t istop = png_ptr->zbuf_size;
+
+   for (i = (png_size_t)skip; i > istop; i -= istop)
+   {
+      png_crc_read(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
+   }
+   if (i)
+   {
+      png_crc_read(png_ptr, png_ptr->zbuf, i);
+   }
+
+   if (png_crc_error(png_ptr))
+   {
+      if (((png_ptr->chunk_name[0] & 0x20) &&                /* Ancillary */
+           !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) ||
+          (!(png_ptr->chunk_name[0] & 0x20) &&             /* Critical  */
+          (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)))
+      {
+         png_chunk_warning(png_ptr, "CRC error");
+      }
+      else
+      {
+         png_chunk_error(png_ptr, "CRC error");
+      }
+      return (1);
+   }
+
+   return (0);
+}
+
+/*
+ * Modify the info structure to reflect the transformations.  The
+ * info should be updated so a PNG file could be written with it,
+ * assuming the transformations result in valid PNG data.
+ */
+void /* PRIVATE */
+png_read_transform_info(png_structp png_ptr, png_infop info_ptr)
+{
+   png_debug(1, "in png_read_transform_info\n");
+#if defined(PNG_READ_EXPAND_SUPPORTED)
+   if (png_ptr->transformations & PNG_EXPAND)
+   {
+      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+      {
+         if (png_ptr->num_trans)
+            info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
+         else
+            info_ptr->color_type = PNG_COLOR_TYPE_RGB;
+         info_ptr->bit_depth = 8;
+         info_ptr->num_trans = 0;
+      }
+      else
+      {
+         if (png_ptr->num_trans)
+            info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
+         if (info_ptr->bit_depth < 8)
+            info_ptr->bit_depth = 8;
+         info_ptr->num_trans = 0;
+      }
+   }
+#endif
+
+#if defined(PNG_READ_BACKGROUND_SUPPORTED)
+   if (png_ptr->transformations & PNG_BACKGROUND)
+   {
+      info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
+      info_ptr->num_trans = 0;
+      info_ptr->background = png_ptr->background;
+   }
+#endif
+
+#if defined(PNG_READ_GAMMA_SUPPORTED)
+   if (png_ptr->transformations & PNG_GAMMA)
+   {
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+      info_ptr->gamma = png_ptr->gamma;
+#endif
+#ifdef PNG_FIXED_POINT_SUPPORTED
+      info_ptr->int_gamma = png_ptr->int_gamma;
+#endif
+   }
+#endif
+
+#if defined(PNG_READ_16_TO_8_SUPPORTED)
+   if ((png_ptr->transformations & PNG_16_TO_8) && (info_ptr->bit_depth == 16))
+      info_ptr->bit_depth = 8;
+#endif
+
+#if defined(PNG_READ_DITHER_SUPPORTED)
+   if (png_ptr->transformations & PNG_DITHER)
+   {
+      if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
+         (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) &&
+         png_ptr->palette_lookup && info_ptr->bit_depth == 8)
+      {
+         info_ptr->color_type = PNG_COLOR_TYPE_PALETTE;
+      }
+   }
+#endif
+
+#if defined(PNG_READ_PACK_SUPPORTED)
+   if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8))
+      info_ptr->bit_depth = 8;
+#endif
+
+#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED)
+   if (png_ptr->transformations & PNG_GRAY_TO_RGB)
+      info_ptr->color_type |= PNG_COLOR_MASK_COLOR;
+#endif
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+   if (png_ptr->transformations & PNG_RGB_TO_GRAY)
+      info_ptr->color_type &= ~PNG_COLOR_MASK_COLOR;
+#endif
+
+   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
+      info_ptr->channels = 1;
+   else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
+      info_ptr->channels = 3;
+   else
+      info_ptr->channels = 1;
+
+#ifndef PNG_FLAG_ADD_ALPHA
+#define PNG_FLAG_ADD_ALPHA          0x200000L  /* Added to libpng-1.2.8 */
+#endif
+#ifndef PNG_FLAG_STRIP_ALPHA
+#define PNG_FLAG_STRIP_ALPHA        0x400000L  /* Added to libpng-1.2.8 */
+#endif
+#ifndef PNG_ADD_ALPHA
+#define PNG_ADD_ALPHA       0x1000000L  /* Added to libpng-1.2.7 */
+#endif
+
+#if defined(PNG_READ_STRIP_ALPHA_SUPPORTED)
+   if (png_ptr->flags & PNG_FLAG_STRIP_ALPHA)
+      info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA;
+#endif
+
+   if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
+      info_ptr->channels++;
+
+#if defined(PNG_READ_FILLER_SUPPORTED)
+   /* STRIP_ALPHA and FILLER allowed:  MASK_ALPHA bit stripped above */
+   if ((png_ptr->transformations & PNG_FILLER) &&
+       ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) ||
+       (info_ptr->color_type == PNG_COLOR_TYPE_GRAY)))
+   {
+      info_ptr->channels++;
+      /* if adding a true alpha channel not just filler */
+#if !defined(PNG_1_0_X)
+      if (png_ptr->transformations & PNG_ADD_ALPHA)
+        info_ptr->color_type |= PNG_COLOR_MASK_ALPHA;
+#endif
+   }
+#endif
+
+#if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \
+defined(PNG_READ_USER_TRANSFORM_SUPPORTED)
+   if(png_ptr->transformations & PNG_USER_TRANSFORM)
+     {
+       if(info_ptr->bit_depth < png_ptr->user_transform_depth)
+         info_ptr->bit_depth = png_ptr->user_transform_depth;
+       if(info_ptr->channels < png_ptr->user_transform_channels)
+         info_ptr->channels = png_ptr->user_transform_channels;
+     }
+#endif
+
+   info_ptr->pixel_depth = (png_byte)(info_ptr->channels *
+      info_ptr->bit_depth);
+
+#ifndef PNG_ROWBYTES
+/* Added to libpng-1.2.6 JB */
+#define PNG_ROWBYTES(pixel_bits, width) \
+    ((pixel_bits) >= 8 ? \
+    ((width) * (((png_uint_32)(pixel_bits)) >> 3)) : \
+    (( ((width) * ((png_uint_32)(pixel_bits))) + 7) >> 3) )
+#endif
+   info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth,info_ptr->width);
+
+#if !defined(PNG_READ_EXPAND_SUPPORTED)
+   if(png_ptr)
+      return;
+#endif
+}
+
+#if !defined(PNG_NO_STDIO)
+/*
+ * This is the function that does the actual reading of data.  If you are
+ * not reading from a standard C stream, you should create a replacement
+ * read_data function and use it at run time with png_set_read_fn(), rather
+ * than changing the library.
+ */
+#ifndef USE_FAR_KEYWORD
+void PNGAPI
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+   png_size_t check;
+
+   /*
+    * fread() returns 0 on error, so it is OK to store this in a png_size_t
+    * instead of an int, which is what fread() actually returns.
+    */
+#if defined(_WIN32_WCE)
+   if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) )
+      check = 0;
+#else
+   check = (png_size_t)fread(data, (png_size_t)1, length,
+      (png_FILE_p)png_ptr->io_ptr);
+#endif
+
+   if (check != length)
+      png_error(png_ptr, "Read Error");
+}
+#else
+/*
+ * This is the model-independent version. Since the standard I/O library
+ * can't handle far buffers in the medium and small models, we have to copy
+ * the data.
+ */
+
+#define NEAR_BUF_SIZE 1024
+#define MIN(a,b) (a <= b ? a : b)
+
+static void /* PRIVATE */
+png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+   int check;
+   png_byte *n_data;
+   png_FILE_p io_ptr;
+
+   /* Check if data really is near. If so, use usual code. */
+   n_data = (png_byte *)CVT_PTR_NOCHECK(data);
+   io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
+   if ((png_bytep)n_data == data)
+   {
+#if defined(_WIN32_WCE)
+      if ( !ReadFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) )
+         check = 0;
+#else
+      check = fread(n_data, 1, length, io_ptr);
+#endif
+   }
+   else
+   {
+      png_byte buf[NEAR_BUF_SIZE];
+      png_size_t read, remaining, err;
+      check = 0;
+      remaining = length;
+      do
+      {
+         read = MIN(NEAR_BUF_SIZE, remaining);
+#if defined(_WIN32_WCE)
+         if ( !ReadFile((HANDLE)(io_ptr), buf, read, &err, NULL) )
+            err = 0;
+#else
+         err = fread(buf, (png_size_t)1, read, io_ptr);
+#endif
+         png_memcpy(data, buf, read); /* copy far buffer to near buffer */
+         if(err != read)
+            break;
+         else
+            check += err;
+         data += read;
+         remaining -= read;
+      }
+      while (remaining != 0);
+   }
+   if ((png_uint_32)check != (png_uint_32)length)
+      png_error(png_ptr, "read Error");
+}
+#endif
+#endif
+#if !defined(PNG_NO_STDIO)
+/*
+ * This is the function that does the actual writing of data.  If you are
+ * not writing to a standard C stream, you should create a replacement
+ * write_data function and use it at run time with png_set_write_fn(), rather
+ * than changing the library.
+ */
+#ifndef USE_FAR_KEYWORD
+void PNGAPI
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+   png_uint_32 check;
+
+#if defined(_WIN32_WCE)
+   if ( !WriteFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) )
+      check = 0;
+#else
+   check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr));
+#endif
+   if (check != length)
+      png_error(png_ptr, "Write Error");
+}
+#else
+/*
+ * This is the model-independent version. Since the standard I/O library
+ * can't handle far buffers in the medium and small models, we have to copy
+ * the data.
+*/
+
+#define NEAR_BUF_SIZE 1024
+#define MIN(a,b) (a <= b ? a : b)
+
+void PNGAPI
+png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
+{
+   png_uint_32 check;
+   png_byte *near_data;  /* Needs to be "png_byte *" instead of "png_bytep" */
+   png_FILE_p io_ptr;
+
+   /* Check if data really is near. If so, use usual code. */
+   near_data = (png_byte *)CVT_PTR_NOCHECK(data);
+   io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr);
+   if ((png_bytep)near_data == data)
+   {
+#if defined(_WIN32_WCE)
+      if ( !WriteFile(io_ptr, near_data, length, &check, NULL) )
+         check = 0;
+#else
+      check = fwrite(near_data, 1, length, io_ptr);
+#endif
+   }
+   else
+   {
+      png_byte buf[NEAR_BUF_SIZE];
+      png_size_t written, remaining, err;
+      check = 0;
+      remaining = length;
+      do
+      {
+         written = MIN(NEAR_BUF_SIZE, remaining);
+         png_memcpy(buf, data, written); /* copy far buffer to near buffer */
+#if defined(_WIN32_WCE)
+         if ( !WriteFile(io_ptr, buf, written, &err, NULL) )
+            err = 0;
+#else
+         err = fwrite(buf, 1, written, io_ptr);
+#endif
+         if (err != written)
+            break;
+         else
+            check += err;
+         data += written;
+         remaining -= written;
+      }
+      while (remaining != 0);
+   }
+   if (check != length)
+      png_error(png_ptr, "Write Error");
+}
+
+#endif
+#endif
+
+#endif /* !defined(PNGCRUSH_H) */
+
+
+
+/* cexcept interface */
+
+static void png_cexcept_error(png_structp png_ptr, png_const_charp err_msg)
+{
+    if (png_ptr);
+#if (defined(PNGCRUSH_H))
+    if (!strcmp(err_msg, "Too many IDAT's found")) {
+#ifndef PNG_NO_CONSOLE_IO
+        fprintf(stderr, "\nIn %s, correcting ", inname);
+#else
+        png_warning(png_ptr, err_msg);
+#endif
+    } else
+#endif /* defined(PNGCRUSH_H) */
+    {
+        Throw err_msg;
+    }
+}
+
+
+
+
+/* START of code to validate memory allocation and deallocation */
+#ifdef PNG_USER_MEM_SUPPORTED
+
+/*
+ * Allocate memory.  For reasonable files, size should never exceed
+ * 64K.  However, zlib may allocate more then 64K if you don't tell
+ * it not to.  See zconf.h and png.h for more information.  zlib does
+ * need to allocate exactly 64K, so whatever you call here must
+ * have the ability to do that.
+ *
+ * This piece of code can be compiled to validate max 64K allocations
+ * by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K.
+ */
+typedef struct memory_information {
+    png_uint_32 size;
+    png_voidp pointer;
+    struct memory_information FAR *next;
+} memory_information;
+typedef memory_information FAR *memory_infop;
+
+static memory_infop pinformation = NULL;
+static int current_allocation = 0;
+static int maximum_allocation = 0;
+
+
+
+
+png_voidp png_debug_malloc(png_structp png_ptr, png_uint_32 size)
+{
+
+    /*
+     * png_malloc has already tested for NULL; png_create_struct calls
+     * png_debug_malloc directly (with png_ptr == NULL prior to libpng-1.2.0
+     * which is OK since we are not using a user mem_ptr)
+     */
+
+    if (size == 0)
+        return (png_voidp) (NULL);
+
+    /*
+     * This calls the library allocator twice, once to get the requested
+     * buffer and once to get a new free list entry.
+     */
+    {
+        memory_infop pinfo = (memory_infop)png_malloc_default(png_ptr,
+           sizeof *pinfo);
+        pinfo->size = size;
+        current_allocation += size;
+        if (current_allocation > maximum_allocation)
+            maximum_allocation = current_allocation;
+        pinfo->pointer = png_malloc_default(png_ptr, size);
+        pinfo->next = pinformation;
+        pinformation = pinfo;
+        /* Make sure the caller isn't assuming zeroed memory. */
+        png_memset(pinfo->pointer, 0xdd, pinfo->size);
+        if (verbose > 2)
+            fprintf(STDERR, "Pointer %lux allocated %lu bytes\n",
+                    (unsigned long) pinfo->pointer, (unsigned long)size);
+        return (png_voidp) (pinfo->pointer);
+    }
+}
+
+
+
+
+/* Free a pointer.  It is removed from the list at the same time. */
+void png_debug_free(png_structp png_ptr, png_voidp ptr)
+{
+    if (png_ptr == NULL)
+        fprintf(STDERR, "NULL pointer to png_debug_free.\n");
+    if (ptr == 0) {
+#if 0 /* This happens all the time. */
+        fprintf(STDERR, "WARNING: freeing NULL pointer\n");
+#endif
+        return;
+    }
+
+    /* Unlink the element from the list. */
+    {
+        memory_infop FAR *ppinfo = &pinformation;
+        for (;;) {
+            memory_infop pinfo = *ppinfo;
+            if (pinfo->pointer == ptr) {
+                *ppinfo = pinfo->next;
+                current_allocation -= pinfo->size;
+                if (current_allocation < 0)
+                    fprintf(STDERR, "Duplicate free of memory\n");
+                /* We must free the list element too, but first kill
+                   the memory that is to be freed. */
+                memset(ptr, 0x55, pinfo->size);
+                if (verbose > 2)
+                    fprintf(STDERR, "Pointer %lux freed %lu bytes\n",
+                            (unsigned long) ptr, (unsigned long)pinfo->size);
+                png_free_default(png_ptr, pinfo);
+                break;
+            }
+            if (pinfo->next == NULL) {
+                fprintf(STDERR, "Pointer %lux not found\n",
+                    (unsigned long) ptr);
+                break;
+            }
+            ppinfo = &pinfo->next;
+        }
+    }
+
+    /* Finally free the data. */
+    png_free_default(png_ptr, ptr);
+}
+
+#endif /* PNG_USER_MEM_SUPPORTED */
+/* END of code to test memory allocation/deallocation */
+
+
+
+
+void png_crush_pause(void)
+{
+    if (pauses > 0) {
+        char keystroke;
+        fprintf(STDERR, "Press [ENTER] key to continue.\n");
+        keystroke = (char) getc(stdin);
+        keystroke = keystroke;  /* stifle compiler warning */
+    }
+}
+
+
+void png_skip_chunk(png_structp png_ptr)
+{
+  png_byte buff[4];
+  int i;
+  unsigned long length;
+
+  /* read the length field */
+  png_default_read_data(png_ptr, buff, 4);
+  length=buff[3]+(buff[2]<<8)+(buff[1]<<16)+(buff[0]<<24);
+  /* read the chunk name */
+  png_default_read_data(png_ptr, buff, 4);
+  printf("Skipping %c%c%c%c chunk.\n",buff[0],buff[1],
+    buff[2],buff[3]);
+  /* skip the data */
+  for (i=0; i
+
+/* The riscos/acorn support was contributed by Darren Salt. */
+static int fileexists(const char *name)
+{
+# ifdef __acorn
+    int ret;
+    return _swix(8, 3 | 1 << 31, 17, name, &ret) ? 0 : ret;
+# else
+    _kernel_swi_regs r;
+    r.r[0] = 17;
+    r.r[1] = (int) name;
+    return _kernel_swi(8, &r, &r) ? 0 : r.r[0];
+# endif
+}
+
+
+static int filesize(const char *name)
+{
+# ifdef __acorn
+    int ret;
+    return _swix(8, 3 | 1 << 27, 17, name, &ret) ? 0 : ret;
+# else
+    _kernel_swi_regs r;
+    r.r[0] = 17;
+    r.r[1] = (int) name;
+    return _kernel_swi(8, &r, &r) ? 0 : r.r[4];
+# endif
+}
+
+
+static int mkdir(const char *name, int ignored)
+{
+# ifdef __acorn
+    _swi(8, 0x13, 8, name, 0);
+    return 0;
+# else
+    _kernel_swi_regs r;
+    r.r[0] = 8;
+    r.r[1] = (int) name;
+    r.r[4] = r.r[3] = r.r[2] = 0;
+    return (int) _kernel_swi(8 | 1 << 31, &r, &r);
+# endif
+}
+
+
+static void setfiletype(const char *name)
+{
+# ifdef __acorn
+    _swi(8, 7, 18, name, 0xB60);
+# else
+    _kernel_swi_regs r;
+    r.r[0] = 18;
+    r.r[1] = (int) name;
+    r.r[2] = 0xB60;
+    _kernel_swi(8 | 1 << 31, &r, &r);
+# endif
+}
+
+#endif /* ?defined(__riscos) */
+
+
+
+
+/*
+ * GRR:  basically boolean; first arg is chunk name-string (e.g., "tIME" or
+ *       "alla"); second is always full argv[] command line
+ *     - remove_chunks is argv index of *last* -rem arg on command line
+ *       (would be more efficient to build table at time of cmdline processing!)
+ *       (i.e., build removal_list with names or unique IDs or whatever--skip
+ *        excessive string-processing on every single one)
+ *     - reprocesses command line _every_ time called, looking for -rem opts...
+ *     - just like keep_chunk() except that latter sets things_have_changed
+ *       variable and debug stmts say "Removed chunk" (but caller actually does
+ *       so, by choosing not to copy chunk to new file)
+ *     - for any given chunk name, "name" must either match exact command-line
+ *       arg (e.g., -rem fOOb), OR it must match one of the official PNG chunk
+ *       names explicitly listed below AND command-line arg either used all-
+ *       lowercase form or one of "all[ab]" options
+ */
+int keep_unknown_chunk(png_const_charp name, char *argv[])
+{
+    int i;
+    if (remove_chunks == 0)
+        return 1;   /* no -rem options, so always keeping */
+    for (i = 1; i <= remove_chunks; i++) {
+        if (!strncmp(argv[i], "-rem", 4)) {
+            int allb = 0;
+            i++;
+            if (!strncmp(argv[i], "all", 3)) {
+                allb++;  /* all but gamma, but not doing gamma here */
+            }
+            if (!strncmp(argv[i], name, 4) /* exact chunk-name match in args */
+                /* ...or exact match for one of known set, plus args included
+                 * either "alla", "allb", or all-lowercase form of "name" */
+                || (!strncmp(name, "cHRM", 4)
+                    && (!strncmp(argv[i], "chrm", 4) || allb))
+                || (!strncmp(name, "dSIG", 4)
+                    && (!strncmp(argv[i], "dsig", 4) || allb))
+                || (!strncmp(name, "gIFg", 4)
+                    && (!strncmp(argv[i], "gifg", 4) || allb))
+                || (!strncmp(name, "gIFt", 4)
+                    && (!strncmp(argv[i], "gift", 4) || allb))
+                || (!strncmp(name, "gIFx", 4)
+                    && (!strncmp(argv[i], "gifx", 4) || allb))
+                || (!strncmp(name, "hIST", 4)
+                    && (!strncmp(argv[i], "hist", 4) || allb))
+                || (!strncmp(name, "iCCP", 4)
+                    && (!strncmp(argv[i], "iccp", 4) || allb))
+                || (!strncmp(name, "pCAL", 4)
+                    && (!strncmp(argv[i], "pcal", 4) || allb))
+                || (!strncmp(name, "sCAL", 4)
+                    && (!strncmp(argv[i], "scal", 4) || allb))
+                || (!strncmp(name, "sPLT", 4)
+                    && (!strncmp(argv[i], "splt", 4) || allb))
+                || (!strncmp(name, "tIME", 4)
+                    && (!strncmp(argv[i], "time", 4) || allb)))
+            {
+                return 0;
+            }
+        }
+    }
+    return 1;
+}
+
+
+
+
+int keep_chunk(png_const_charp name, char *argv[])
+{
+    int i;
+    if (verbose > 2 && first_trial)
+        fprintf(STDERR, "   Read the %s chunk.\n", name);
+    if (remove_chunks == 0)
+        return 1;
+    if (verbose > 1 && first_trial)
+        fprintf(STDERR, "     Check for removal of the %s chunk.\n", name);
+    for (i = 1; i <= remove_chunks; i++) {
+        if (!strncmp(argv[i], "-rem", 4)) {
+            int alla = 0;
+            int allb = 0;
+            int allt = 0;
+            i++;
+            if (!strncmp(argv[i], "all", 3)) {
+                allt++;         /* all forms of text chunk are ancillary */
+                allb++;         /* all ancillaries but gamma... */
+                if (!strncmp(argv[i], "alla", 4))
+                    alla++;     /* ...no, all ancillaries, period */
+            } else if (!strncmp(argv[i], "text", 4))
+                allt++;         /* all forms of text chunk */
+            if (!strncmp(argv[i], name, 4)  /* exact chunk-name match in args
+                * ...or exact match for one of known set, plus args included
+                * either "alla", "allb", or all-lowercase form of "name": */
+                || (!strncmp(name, "PLTE", 4)
+                    && (!strncmp(argv[i], "plte", 4)        ))
+                || (!strncmp(name, "bKGD", 4)
+                    && (!strncmp(argv[i], "bkgd", 4) || allb))
+                || (!strncmp(name, "cHRM", 4)
+                    && (!strncmp(argv[i], "chrm", 4) || allb))
+                || (!strncmp(name, "dSIG", 4)
+                    && (!strncmp(argv[i], "dsig", 4) || allb))
+                || (!strncmp(name, "gAMA", 4)
+                    && (!strncmp(argv[i], "gama", 4) || alla))
+                || (!strncmp(name, "gIFg", 4)
+                    && (!strncmp(argv[i], "gifg", 4) || allb))
+                || (!strncmp(name, "gIFt", 4)
+                    && (!strncmp(argv[i], "gift", 4) || allb))
+                || (!strncmp(name, "gIFx", 4)
+                    && (!strncmp(argv[i], "gifx", 4) || allb))
+                || (!strncmp(name, "hIST", 4)
+                    && (!strncmp(argv[i], "hist", 4) || allb))
+                || (!strncmp(name, "iCCP", 4)
+                    && (!strncmp(argv[i], "iccp", 4) || allb))
+                || (!strncmp(name, "iTXt", 4)
+                    && (!strncmp(argv[i], "itxt", 4) || allt))
+                || (!strncmp(name, "oFFs", 4)
+                    && (!strncmp(argv[i], "offs", 4) || allb))
+                || (!strncmp(name, "pHYs", 4)
+                    && (!strncmp(argv[i], "phys", 4) || allb))
+                || (!strncmp(name, "pCAL", 4)
+                    && (!strncmp(argv[i], "pcal", 4) || allb))
+                || (!strncmp(name, "sBIT", 4)
+                    && (!strncmp(argv[i], "sbit", 4) || allb))
+                || (!strncmp(name, "sCAL", 4)
+                    && (!strncmp(argv[i], "scal", 4) || allb))
+                || (!strncmp(name, "sRGB", 4)
+                    && (!strncmp(argv[i], "srgb", 4) || allb))
+                || (!strncmp(name, "sTER", 4)
+                    && (!strncmp(argv[i], "ster", 4) || allb))
+                || (!strncmp(name, "sPLT", 4)
+                    && (!strncmp(argv[i], "splt", 4) || allb))
+                || (!strncmp(name, "tEXt", 4)
+                    && (                                allt))
+                || (!strncmp(name, "tIME", 4)
+                    && (!strncmp(argv[i], "time", 4) || allb))
+                || (!strncmp(name, "tRNS", 4)
+                    && (!strncmp(argv[i], "trns", 4)        ))
+                || (!strncmp(name, "zTXt", 4)
+                    && (!strncmp(argv[i], "ztxt", 4) || allt)) )
+            {
+                things_have_changed = 1;
+                /* (caller actually does the removal--by failing to create
+                 * copy) */
+                if (verbose > 0 && first_trial)
+                    fprintf(STDERR, "   Removed the %s chunk.\n", name);
+                return 0;
+            }
+        }
+    }
+    if (verbose > 1 && first_trial)
+        fprintf(STDERR, "   Preserving the %s chunk.\n", name);
+    return 1;
+}
+
+
+
+
+void show_result(void)
+{
+    if (total_output_length) {
+        if (total_input_length == total_output_length)
+            fprintf(STDERR, "   Overall result: no change\n");
+        else if (total_input_length > total_output_length)
+            fprintf(STDERR,
+                    "   Overall result: %4.2f%% reduction, %lu bytes\n",
+                    (100.0 -
+                     (100.0 * total_output_length) / total_input_length),
+                    (unsigned long)(total_input_length-total_output_length));
+        else
+            fprintf(STDERR,
+                    "   Overall result: %4.2f%% increase, %lu bytes\n",
+                    -(100.0 -
+                      (100.0 * total_output_length) / total_input_length),
+                    (unsigned long)(total_output_length - total_input_length));
+    }
+    t_stop = (TIME_T) clock();
+    t_misc += (t_stop - t_start);
+    if (t_stop < t_start) {
+        t_misc += PNG_UINT_31_MAX;
+        if (t_stop < 0)
+            t_misc += PNG_UINT_31_MAX;
+    }
+    t_start = t_stop;
+    fprintf(STDERR, "   CPU time used = %.3f seconds",
+            (t_misc + t_decode + t_encode) / (float) CLOCKS_PER_SEC);
+    fprintf(STDERR, " (decoding %.3f,\n",
+            t_decode / (float) CLOCKS_PER_SEC);
+    fprintf(STDERR, "          encoding %.3f,",
+            t_encode / (float) CLOCKS_PER_SEC);
+    fprintf(STDERR, " other %.3f seconds)\n\n",
+            t_misc / (float) CLOCKS_PER_SEC);
+#ifdef PNG_USER_MEM_SUPPORTED
+    if (current_allocation) {
+        memory_infop pinfo = pinformation;
+        fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n",
+                current_allocation);
+        while (pinfo != NULL) {
+            fprintf(STDERR, " %8lu bytes at %lux\n", (unsigned long)pinfo->size,
+                    (unsigned long) pinfo->pointer);
+            free(pinfo->pointer);
+            pinfo = pinfo->next;
+        }
+    }
+#endif
+}
+
+
+
+
+int main(int argc, char *argv[])
+{
+    png_uint_32 y;
+    int bit_depth, color_type;
+    int num_pass, pass;
+    int num_methods;
+    int try_method[MAX_METHODSP1];
+    int fm[MAX_METHODSP1];
+    int lv[MAX_METHODSP1];
+    int zs[MAX_METHODSP1];
+    int lev, strat, filt;
+#ifdef PNG_gAMA_SUPPORTED
+#ifdef PNG_FIXED_POINT_SUPPORTED
+    png_fixed_point file_gamma = 0;
+#else
+    double file_gamma = 0.;
+#endif
+#endif
+    char *cp;
+    int i;
+    row_buf = (png_bytep) NULL;
+    number_of_open_files = 0;
+#ifdef PNGCRUSH_COUNT_COLORS
+    reduce_to_gray = 0;
+    it_is_opaque = 0;
+#else
+    do_color_count = 0;
+    do_color_count = do_color_count;    /* silence compiler warning */
+#endif
+
+    if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING)) {
+        fprintf(STDERR,
+                "Warning: versions are different between png.h and png.c\n");
+        fprintf(STDERR, "  png.h version: %s\n", PNG_LIBPNG_VER_STRING);
+        fprintf(STDERR, "  png.c version: %s\n\n", png_libpng_ver);
+    }
+
+    t_start = (TIME_T) clock();
+
+    strncpy(prog_string, argv[0], STR_BUF_SIZE);
+    prog_string[STR_BUF_SIZE-1] = '\0';
+    progname = prog_string;
+    for (i = 0, cp = prog_string; *cp != '\0'; i++, cp++) {
+#ifdef __riscos
+        if (*cp == '.' || *cp == ':')
+            progname = ++cp;
+#else
+        if (*cp == '\\' || *cp == '/')
+            progname = ++cp;
+        if (*cp == '.')
+            *cp = '\0';
+#endif
+    }
+
+    /*
+     * Definition of methods ("canonical list" is methods 11 and up)
+     */
+    for (i = 0; i < MAX_METHODS; i++) {
+        try_method[i] = 1;
+        fm[i] = 5; lv[i] = 9; zs[i] = 1;  /* default:  method 124 */
+    }
+
+    fm[1] = 0; lv[1] = 4; zs[1] = 0;   /* method  1 == method  53 */
+    fm[2] = 1; lv[2] = 4; zs[2] = 0;   /* method  2 == method  54 */
+               lv[3] = 4;              /* method  3 == method  64 */
+    fm[4] = 0;                         /* method  4 == method 119 */
+    fm[5] = 1;            zs[5] = 0;   /* method  5 == method 114 */
+                          zs[6] = 0;   /* method  6 == method 118 */
+    fm[7] = 0;            zs[7] = 0;   /* method  7 == method 113 */
+    fm[8] = 1;                         /* method  8 == method 120 */
+               lv[9] = 2; zs[9] = 2;   /* method  9 == method  16 */
+                                       /* method 10 == method 124 */
+
+    /* methods 11 through 16
+     *
+     * [strategy 2 (Z_HUFFMAN_ONLY) is independent of zlib compression level]
+     */
+    method = 11;
+    for (filt = 0; filt <= 5; filt++) {
+        fm[method] = filt;
+        lv[method] = 2;
+        zs[method] = 2;
+        method++;
+    }
+
+    /*
+     * methods 17 through 124 (9*2*6 = 108)
+     */
+    for (lev = 1; lev <= 9; lev++) {
+        for (strat = 0; strat <= 1; strat++) {
+            for (filt = 0; filt <= 5; filt++) {
+                fm[method] = filt;
+                lv[method] = lev;
+                zs[method] = strat;
+                method++;
+            }
+        }
+    }
+
+#ifdef Z_RLE
+    /* methods 125 through 136
+     *
+     * [strategy 3 (Z_RLE) is mostly independent of level; 1-3 and 4-9 are
+     * same]
+     */
+    for (filt = 0; filt <= 5; filt++) {
+        fm[method] = filt;
+        lv[method] = 1;
+        zs[method] = 3;
+        method++;
+    }
+    for (filt = 0; filt <= 5; filt++) {
+        fm[method] = filt;
+        lv[method] = 4;
+        zs[method] = 3;
+        method++;
+    }
+#endif /* Z_RLE */
+
+    num_methods = method;   /* GRR */
+
+
+#define BUMP_I i++;if(i >= argc) {printf("insufficient parameters\n");exit(1);}
+    names = 1;
+
+    /* ===================================================================== */
+    /* FIXME:  move args-processing block into separate function (470 lines) */
+    for (i = 1; i < argc; i++) {
+        if (!strncmp(argv[i], "-", 1))
+            names++;
+
+
+        /* GRR:  start of giant else-if block */
+        if (!strncmp(argv[i], "-fast", 5)) {
+            /* try two fast filters */
+            methods_specified = 1;
+            try_method[16] = 0;
+            try_method[53] = 0;
+        } else if (!strncmp(argv[i], "-huffman", 8)) {
+            /* try all filters with huffman */
+            methods_specified = 1;
+            for (method = 11; method <= 16; method++) {
+                try_method[method] = 0;
+            }
+#ifdef Z_RLE
+        } else if (!strncmp(argv[i], "-rle", 4)) {
+            /* try all filters with RLE */
+            methods_specified = 1;
+            for (method = 125; method <= 136; method++) {
+                try_method[method] = 0;
+            }
+#endif
+        }
+
+        else if (!strncmp(argv[i], "-already", 8)) {
+            names++;
+            BUMP_I;
+            crushed_idat_size = (png_uint_32) atoi(argv[i]);
+        }
+
+        else if (!strncmp(argv[i], "-bkgd", 5) ||
+                 !strncmp(argv[i], "-bKGD", 5))
+        {
+            names += 3;
+            have_bkgd = 1;
+            bkgd_red = (png_uint_16) atoi(argv[++i]);
+            bkgd_green = (png_uint_16) atoi(argv[++i]);
+            bkgd_blue = (png_uint_16) atoi(argv[++i]);
+        }
+
+        else if (!strncmp(argv[i], "-brute", 6))
+            /* brute force:  try everything */
+        {
+            methods_specified = 1;
+            brute_force++;
+            for (method = 11; method < num_methods; method++)
+                try_method[method] = 0;
+            if (brute_force_filter == 0)
+                for (filt = 0; filt < 6; filt++)
+                    brute_force_filters[filt] = 0;
+            if (brute_force_level == 0)
+                for (lev = 0; lev < 10; lev++)
+                    brute_force_levels[lev] = 0;
+            if (brute_force_strategy == 0)
+                for (strat = 0; strat < NUM_STRATEGIES; strat++)
+                    brute_force_strategies[strat] = 0;
+        } else if (!strncmp(argv[i], "-bit_depth", 10)) {
+            names++;
+            BUMP_I;
+            force_output_bit_depth = atoi(argv[i]);
+        } else if (!strncmp(argv[i], "-cc", 3)) {
+            do_color_count = 1;
+        } else if (!strncmp(argv[i], "-no_cc", 6)) {
+            do_color_count = 0;
+        } else if (!strncmp(argv[i], "-c", 2)) {
+            names++;
+            BUMP_I;
+            force_output_color_type = atoi(argv[i]);
+        }
+#ifdef PNG_gAMA_SUPPORTED
+        else if (!strncmp(argv[i], "-dou", 4)) {
+            double_gamma++;
+            found_gAMA=1;
+            global_things_have_changed = 1;
+        }
+#endif
+        else if (!strncmp(argv[i], "-d", 2)) {
+            BUMP_I;
+            if (pngcrush_mode == EXTENSION_MODE)
+                pngcrush_mode = DIREX_MODE;
+            else
+                pngcrush_mode = DIRECTORY_MODE;
+            directory_name = argv[names++];
+        } else if (!strncmp(argv[i], "-exit", 5)) {
+            pngcrush_must_exit = 1;
+        } else if (!strncmp(argv[i], "-e", 2)) {
+            BUMP_I;
+            if (pngcrush_mode == DIRECTORY_MODE)
+                pngcrush_mode = DIREX_MODE;
+            else
+                pngcrush_mode = EXTENSION_MODE;
+            extension = argv[names++];
+        } else if (!strncmp(argv[i], "-force", 6)) {
+            global_things_have_changed = 1;
+        } else if (!strncmp(argv[i], "-fix", 4)) {
+            fix++;
+        } else if (!strncmp(argv[i], "-f", 2)) {
+            int specified_filter = atoi(argv[++i]);
+            if (specified_filter > 5 || specified_filter < 0)
+                specified_filter = 5;
+            names++;
+            if (brute_force == 0)
+                fm[method] = specified_filter;
+            else {
+                for (filt = 0; filt < 6; filt++)
+                    brute_force_filters[filt] = 1;
+                brute_force_filters[specified_filter] = 0;
+                method = 11;
+                for (filt = 0; filt < 6; filt++) {
+                    try_method[method] = brute_force_filters[filt] |
+                        brute_force_strategies[2];
+                    method++;
+                }
+                for (lev = 1; lev < 10; lev++) {
+                    for (strat = 0; strat < 2; strat++) {
+                        for (filt = 0; filt < 6; filt++) {
+                            try_method[method] = brute_force_levels[lev] |
+                                brute_force_filters[filt] |
+                                brute_force_strategies[strat];
+                            method++;
+                        }
+                    }
+                }
+                brute_force_filter++;
+            }
+        } else if (!strncmp(argv[i], "-loco", 5)) {
+#ifdef PNGCRUSH_LOCO
+            do_loco = 1;
+#else
+            printf
+                ("Cannot do -loco because libpng was compiled"
+                 " without MNG features");
+#endif
+        } else if (!strncmp(argv[i], "-l", 2)) {
+            int specified_level = atoi(argv[++i]);
+            if (specified_level > 9 || specified_level < 0)
+                specified_level = 9;
+            names++;
+            if (brute_force == 0)
+                lv[method] = specified_level;
+            else {
+                if (brute_force_level == 0)
+                    for (lev = 0; lev < 10; lev++)
+                        brute_force_levels[lev] = 1;
+                brute_force_levels[specified_level] = 0;
+                method = 11;
+                for (filt = 0; filt < 6; filt++) {
+                    lv[method] = specified_level;
+                    method++;
+                }
+                for (lev = 1; lev < 10; lev++) {
+                    for (strat = 0; strat < 2; strat++) {
+                        for (filt = 0; filt < 6; filt++) {
+                            try_method[method] = brute_force_levels[lev] |
+                                brute_force_filters[filt] |
+                                brute_force_strategies[strat];
+                            method++;
+                        }
+                    }
+                }
+                brute_force_level++;
+            }
+        }
+#ifdef PNG_gAMA_SUPPORTED
+        else if (!strncmp(argv[i], "-g", 2)) {
+            names++;
+            BUMP_I;
+            found_gAMA=1;
+            if (intent < 0) {
+#ifdef PNG_FIXED_POINT_SUPPORTED
+                int c;
+                char number[16];
+                char *n = number;
+                int nzeroes = -1;
+                int length = strlen(argv[i]);
+                for (c = 0; c < length; c++) {
+                    if (*(argv[i] + c) == '.') {
+                        nzeroes = 5;
+                    } else if (nzeroes) {
+                        *n++ = *(argv[i] + c);
+                        nzeroes--;
+                    }
+                }
+                for (c = 0; c < nzeroes; c++)
+                    *n++ = '0';
+                *n = '\0';
+                specified_gamma = atoi(number);
+#else
+                specified_gamma = atof(argv[i]);
+#endif
+            }
+        }
+#endif /* PNG_gAMA_SUPPORTED */
+        else if (!strncmp(argv[i], "-h", 2)) {
+            ++verbose;
+            print_version_info();
+            print_usage(0);   /* this exits */
+        }
+#ifdef PNG_iCCP_SUPPORTED
+        else if (!strncmp(argv[i], "-iccp", 5)) {
+            FILE *iccp_fn;
+            if (iccp_length)
+                free(iccp_text);
+            iccp_length = atoi(argv[++i]);
+            names += 3;
+            strcpy(iccp_name, argv[++i]);
+            iccp_file = argv[++i];
+            if ((iccp_fn = FOPEN(iccp_file, "rb")) == NULL) {
+                fprintf(STDERR, "Could not find file: %s\n", iccp_file);
+                iccp_length = 0;
+            } else {
+                int ic;
+                iccp_text = (char*)malloc(iccp_length);
+                for (ic = 0; ic < iccp_length; ic++) {
+                    png_size_t num_in;
+                    num_in = fread(buffer, 1, 1, iccp_fn);
+                    if (!num_in)
+                        break;
+                    iccp_text[ic] = buffer[0];
+                }
+            }
+        }
+#endif
+        else if (!strncmp(argv[i], "-keep", 5)) {
+            names++;
+            BUMP_I;
+            if (!strncmp(argv[i], "dSIG", 4)
+                    && (!strncmp(argv[i], "dsig", 4) ))
+              found_any_chunk=1;
+        }
+
+        else if (!strncmp(argv[i], "-max", 4)) {
+            names++;
+            BUMP_I;
+            max_idat_size = (png_uint_32) atoi(argv[i]);
+            if (max_idat_size == 0 || max_idat_size > PNG_UINT_31_MAX)
+                max_idat_size = PNG_ZBUF_SIZE;
+#ifdef PNGCRUSH_LOCO
+        } else if (!strncmp(argv[i], "-mng", 4)) {
+            names++;
+            BUMP_I;
+            mngname = argv[i];
+            new_mng++;
+#endif
+        } else if (!strncmp(argv[i], "-m", 2)) {
+            names++;
+            BUMP_I;
+            method = atoi(argv[i]);
+            methods_specified = 1;
+            brute_force = 0;
+            try_method[method] = 0;
+        } else if (!strncmp(argv[i], "-nofilecheck", 5)) {
+            nofilecheck++;
+        } else if (!strncmp(argv[i], "-nosave", 2)) {
+            /* no save; I just use this for testing decode speed */
+            /* also to avoid saving if a CgBI chunk was found */
+            nosave++;
+            pngcrush_mode = EXTENSION_MODE;
+        } else if (!strncmp(argv[i], "-oldtimestamp", 5)) {
+            new_time_stamp=0;
+        } else if (!strncmp(argv[i], "-plte_len", 9)) {
+            names++;
+            BUMP_I;
+            plte_len = atoi(argv[i]);
+        } else if (!strncmp(argv[i], "-pplt", 3)) {
+            names++;
+            do_pplt++;
+            BUMP_I;
+            strcpy(pplt_string, argv[i]);
+            global_things_have_changed = 1;
+        } else if (!strncmp(argv[i], "-p", 2)) {
+            pauses++;
+        } else if (!strncmp(argv[i], "-q", 2)) {
+            verbose = 0;
+        } else if (!strncmp(argv[i], "-reduce", 7)) {
+            reduction_ok++;
+            do_color_count = 1;
+        }
+#ifdef PNG_gAMA_SUPPORTED
+        else if (!strncmp(argv[i], "-replace_gamma", 4)) {
+            names++;
+            BUMP_I;
+            found_gAMA=1;
+            {
+#ifdef PNG_FIXED_POINT_SUPPORTED
+                int c;
+                char number[16];
+                char *n = number;
+                int nzeroes = -1;
+                int length = strlen(argv[i]);
+                for (c = 0; c < length; c++) {
+                    if (*(argv[i] + c) == '.') {
+                        nzeroes = 5;
+                    } else if (nzeroes) {
+                        *n++ = *(argv[i] + c);
+                        nzeroes--;
+                    }
+                }
+                for (c = 0; c < nzeroes; c++)
+                    *n++ = '0';
+                *n = '\0';
+                force_specified_gamma = atoi(number);
+#else
+                force_specified_gamma = atof(argv[i]);
+#endif
+            }
+            global_things_have_changed = 1;
+        }
+#endif
+#ifdef PNG_pHYs_SUPPORTED
+        else if (!strncmp(argv[i], "-res", 4)) {
+            names++;
+            BUMP_I;
+            resolution = atoi(argv[i]);
+            global_things_have_changed = 1;
+        }
+#endif
+#ifdef PNGCRUSH_MULTIPLE_ROWS
+        else if (!strncmp(argv[i], "-rows", 5)) {
+            names++;
+            BUMP_I;
+            max_rows_at_a_time = atoi(argv[i]);
+        }
+#endif
+        else if (!strncmp(argv[i], "-r", 2)) {
+            remove_chunks = i;
+            names++;
+            BUMP_I;
+            if (!strncmp(argv[i], "dSIG", 4)
+                 && (!strncmp(argv[i], "dsig", 4)))
+               image_is_immutable=0;
+        } else if (!strncmp(argv[i], "-save", 5)) {
+            all_chunks_are_safe++;
+        } else if (!strncmp(argv[i], "-srgb", 5) ||
+                   !strncmp(argv[i], "-sRGB", 5)) {
+#ifdef PNG_gAMA_SUPPORTED
+#ifdef PNG_FIXED_POINT_SUPPORTED
+            specified_gamma = 45455L;
+#else
+            specified_gamma = 0.45455;
+#endif
+#endif
+            intent = 0;
+            BUMP_I;
+            if (!strncmp(argv[i], "0", 1) ||
+                !strncmp(argv[i], "1", 1) ||
+                !strncmp(argv[i], "2", 1) || !strncmp(argv[i], "3", 1)) {
+                names++;
+                intent = (int) atoi(argv[i]);
+                global_things_have_changed = 1;
+            } else
+                i--;
+        } else if (!strncmp(argv[i], "-ster", 5) ||
+                   !strncmp(argv[i], "-sTER", 5)) {
+            BUMP_I;
+            ster_mode = -1;
+            if (!strncmp(argv[i], "0", 1) ||
+                !strncmp(argv[i], "1", 1)) {
+                names++;
+                ster_mode = (int) atoi(argv[i]);
+                global_things_have_changed = 1;
+            } else
+                i--;
+        } else if (!strncmp(argv[i], "-s", 2)) {
+            verbose = 0;
+        } else if (!strncmp(argv[i], "-text", 5)
+                 || !strncmp(argv[i], "-tEXt", 5) ||
+#ifdef PNG_iTXt_SUPPORTED
+                 !strncmp(argv[i], "-itxt", 5)
+                 || !strncmp(argv[i], "-iTXt", 5)
+                 || !strncmp(argv[i], "-zitxt", 6)
+                 || !strncmp(argv[i], "-ziTXt", 6) ||
+#endif
+                 !strncmp(argv[i], "-ztxt", 5)
+                 || !strncmp(argv[i], "-zTXt", 5))
+        {
+            i += 2;
+            BUMP_I;
+            i -= 3;
+            if (strlen(argv[i + 2]) < 180 && strlen(argv[i + 3]) < 2048 &&
+                text_inputs < 10) {
+#ifdef PNG_iTXt_SUPPORTED
+                if (!strncmp(argv[i], "-zi", 3)) {
+                    text_compression[text_inputs] =
+                        PNG_ITXT_COMPRESSION_zTXt;
+                    /* names += 2; */
+                } else
+#endif
+                if (!strncmp(argv[i], "-z", 2))
+                    text_compression[text_inputs] =
+                        PNG_TEXT_COMPRESSION_zTXt;
+                else if (!strncmp(argv[i], "-t", 2))
+                    text_compression[text_inputs] =
+                        PNG_TEXT_COMPRESSION_NONE;
+#ifdef PNG_iTXt_SUPPORTED
+                else {
+                    text_compression[text_inputs] =
+                        PNG_ITXT_COMPRESSION_NONE;
+                    /* names += 2; */
+                }
+#endif
+                names += 3;
+                if (!strncmp(argv[++i], "b", 1))
+                    text_where[text_inputs] = 1;
+                if (!strncmp(argv[i], "a", 1))
+                    text_where[text_inputs] = 2;
+                strcpy(&text_keyword[text_inputs * 80], argv[++i]);
+#ifdef PNG_iTXt_SUPPORTED
+                if (text_compression[text_inputs] <= 0) {
+                    text_lang[text_inputs * 80] = '\0';
+                    text_lang_key[text_inputs * 80] = '\0';
+                } else {
+                    i += 2;
+                    BUMP_I;
+                    i -= 3;
+                    names += 2;
+                    strcpy(&text_lang[text_inputs * 80], argv[++i]);
+                    /* libpng-1.0.5j and later */
+                    strcpy(&text_lang_key[text_inputs * 80], argv[++i]);
+                }
+#endif
+                strcpy(&text_text[text_inputs * 2048], argv[++i]);
+                text_inputs++;
+            } else {
+                if (text_inputs > 9)
+                    fprintf(STDERR,
+                            "too many text/zTXt inputs; only 10 allowed\n");
+                else
+                    fprintf(STDERR,
+                            "keyword exceeds 79 characters or text"
+                            " exceeds 2047 characters\n");
+                i += 3;
+                names += 3;
+#ifdef PNG_iTXt_SUPPORTED
+                if (!strncmp(argv[i], "-i", 2)
+                    || !strncmp(argv[i], "-zi", 3)) {
+                    i++;
+                    BUMP_I;
+                    names += 2;
+                }
+#endif
+            }
+        }
+        else if (!strncmp(argv[i], "-time_stamp", 5) ||  /* legacy */
+                 !strncmp(argv[i], "-newtimestamp", 5))
+            new_time_stamp=1;
+
+#ifdef PNG_tRNS_SUPPORTED
+        else if (!strncmp(argv[i], "-trns_a", 7) ||
+                 !strncmp(argv[i], "-tRNS_a", 7)) {
+            num_trans_in = (png_uint_16) atoi(argv[++i]);
+            trns_index=num_trans_in-1;
+            have_trns = 1;
+            for (ia = 0; ia < num_trans_in; ia++)
+                trans_in[ia] = (png_byte) atoi(argv[++i]);
+            names += 1 + num_trans_in;
+        } else if (!strncmp(argv[i], "-trns", 5) ||
+                   !strncmp(argv[i], "-tRNS", 5)) {
+            names += 5;
+            have_trns = 1;
+            trns_index = (png_uint_16) atoi(argv[++i]);
+            trns_red = (png_uint_16) atoi(argv[++i]);
+            trns_green = (png_uint_16) atoi(argv[++i]);
+            trns_blue = (png_uint_16) atoi(argv[++i]);
+            trns_gray = (png_uint_16) atoi(argv[++i]);
+        }
+#endif
+        else if (!strncmp(argv[i], "-version", 8)) {
+            fprintf(STDERR, " pngcrush ");
+            fprintf(STDERR, PNGCRUSH_VERSION);
+            fprintf(STDERR, ", uses libpng ");
+            fprintf(STDERR, PNG_LIBPNG_VER_STRING);
+            fprintf(STDERR, " and zlib ");
+            fprintf(STDERR, ZLIB_VERSION);
+            fprintf(STDERR, "\n Check http://pmt.sf.net/\n");
+            fprintf(STDERR, " for the most recent version.\n");
+            verbose = 0;
+        } else if (!strncmp(argv[i], "-v", 2)) {
+            verbose++;
+        } else if (!strncmp(argv[i], "-w", 2)) {
+            default_compression_window = atoi(argv[++i]);
+            force_compression_window++;
+            names++;
+        } else if (!strncmp(argv[i], "-zm", 3)) {
+            compression_mem_level = atoi(argv[++i]);
+            names++;
+        } else if (!strncmp(argv[i], "-z", 2)) {
+            int specified_strategy = atoi(argv[++i]);
+            if (specified_strategy > 2 || specified_strategy < 0)
+                specified_strategy = 0;
+            names++;
+            if (brute_force == 0)
+                zs[method] = specified_strategy;
+            else {
+                if (brute_force_strategy == 0)
+                    for (strat = 0; strat < 2; strat++)
+                        brute_force_strategies[strat] = 1;
+                brute_force_strategies[specified_strategy] = 0;
+                method = 11;
+                for (filt = 0; filt < 6; filt++) {
+                    if (specified_strategy != 2)
+                        try_method[method] = 1;
+                    method++;
+                }
+                for (lev = 1; lev < 10; lev++) {
+                    for (strat = 0; strat < 2; strat++) {
+                        for (filt = 0; filt < 6; filt++) {
+                            try_method[method] = brute_force_levels[lev] |
+                                brute_force_filters[filt] |
+                                brute_force_strategies[strat];
+                            method++;
+                        }
+                    }
+                }
+            }
+            brute_force_strategy++;
+        } /* GRR:  end of giant if-else block */
+    } /* end of loop over args ============================================ */
+
+
+    if (verbose > 0)
+        print_version_info();
+
+    if (default_compression_window == 32)
+        default_compression_window = 15;
+    else if (default_compression_window == 16)
+        default_compression_window = 14;
+    else if (default_compression_window == 8)
+        default_compression_window = 13;
+    else if (default_compression_window == 4)
+        default_compression_window = 12;
+    else if (default_compression_window == 2)
+        default_compression_window = 11;
+    else if (default_compression_window == 1)
+        default_compression_window = 10;
+    else if (default_compression_window == 512)
+        default_compression_window = 9;
+    /* Use of compression window size 256 is not recommended. */
+    else if (default_compression_window == 256)
+        default_compression_window = 8;
+    else if (default_compression_window != 15) {
+        fprintf(STDERR, "Invalid window size (%d); using window size=4\n",
+                default_compression_window);
+        default_compression_window = 12;
+    }
+
+    if (pngcrush_mode == DEFAULT_MODE) {
+        if (argc - names == 2) {
+            inname = argv[names];
+            outname = argv[names + 1];
+        } else {
+            if ((argc - names == 1 || nosave)) {
+                inname = argv[names];
+            }
+            if (verbose && !nosave) {
+                print_usage(1);   /* this exits */
+            }
+        }
+    }
+
+    for (ia = 0; ia < 256; ia++)
+        trns_array[ia]=255;
+
+    for (;;)  /* loop on input files */
+    {
+        first_trial = 1;
+
+        things_have_changed = global_things_have_changed;
+
+        if (png_row_filters != NULL) {
+            free(png_row_filters);
+            png_row_filters = NULL;
+        }
+
+        image_specified_gamma = 0;
+
+        inname = argv[names++];
+
+        if (inname == NULL) {
+            if (verbose > 0)
+                show_result();
+            break;
+        }
+
+        if (pngcrush_mode == DIRECTORY_MODE || pngcrush_mode == DIREX_MODE) {
+            int inlen, outlen;
+#ifndef __riscos
+            struct stat stat_buf;
+            if (stat(directory_name, &stat_buf))
+#else
+            if (fileexists(directory_name) & 2)
+#endif
+            {
+#if defined(_MBCS) || defined(WIN32) || defined(__WIN32__)
+                if (_mkdir(directory_name))
+#else
+                if (mkdir(directory_name, 0755))
+#endif
+                {
+                    fprintf(STDERR, "could not create directory %s\n",
+                      directory_name);
+                    exit(1);
+                }
+                nofilecheck = 1;
+            }
+            outlen = strlen(directory_name);
+            if (outlen >= STR_BUF_SIZE-1) {
+                fprintf(STDERR, "directory %s is too long for buffer\n",
+                  directory_name);
+                exit(1);
+            }
+            strcpy(out_string, directory_name);
+            /*strcpy(out_string+outlen, SLASH); */
+            out_string[outlen++] = SLASH[0];   /* (assuming SLASH is 1 byte) */
+            out_string[outlen] = '\0';
+
+            inlen = strlen(inname);
+            if (inlen >= STR_BUF_SIZE) {
+                fprintf(STDERR, "filename %s is too long for buffer\n", inname);
+                exit(1);
+            }
+            strcpy(in_string, inname);
+            in_string[inlen] = '\0';
+#ifdef __riscos
+            op = strrchr(in_string, '.');
+            if (!op)
+                op = in_string;
+            else
+                op++;
+#else
+            op = in_string;
+            ip = in_string + inlen - 1;   /* start at last char in string */
+            while (ip > in_string) {
+                if (*ip == '\\' || *ip == '/') {
+                    op = ip + 1;
+                    break;
+                }
+                --ip;
+            }
+#endif
+
+            if (outlen + (inlen - (op - in_string)) >= STR_BUF_SIZE) {
+                fprintf(STDERR, "full path is too long for buffer\n");
+                exit(1);
+            }
+            strcpy(out_string+outlen, op);
+            /*outlen += inlen - (op - in_string); */
+            outname = out_string;
+        }
+
+        /*
+         * FIXME:  need same input-validation fixes (as above) here, too
+         *
+         * FIXME:  what was the point of setting in_string and out_string in
+         *         DIREX_MODE above if going to do all over again here?
+         */
+        if (pngcrush_mode == EXTENSION_MODE || pngcrush_mode == DIREX_MODE) {
+            ip = in_string;
+            in_string[0] = '\0';
+            if (pngcrush_mode == EXTENSION_MODE)
+                strcat(in_string, inname);
+            else
+                strcat(in_string, outname);
+            ip = in_string;
+            op = dot = out_string;
+            while (*ip != '\0') {
+                *op++ = *ip++;
+#ifdef __riscos
+                if (*ip == '/')
+                    dot = op;
+#else
+                if (*ip == '.')
+                    dot = op;
+#endif
+            }
+            *op = '\0';
+
+            if (dot != out_string)
+                *dot = '\0';
+
+            in_extension[0] = '\0';
+            if (dot != out_string) {
+                strcat(in_extension, ++dot);
+            }
+
+            strcat(out_string, extension);
+            outname = out_string;
+        }
+
+
+        if (nosave < 2) {
+            P1( "Opening file %s for length measurement\n",
+                       inname);
+
+            if ((fpin = FOPEN(inname, "rb")) == NULL) {
+                fprintf(STDERR, "Could not find file: %s\n", inname);
+                continue;
+            }
+            number_of_open_files++;
+
+            already_crushed = 0;
+
+#ifdef PNGCRUSH_LOCO
+            if (new_mng) {
+           
+#ifdef PNG_USER_MEM_SUPPORTED
+               mng_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
+                 (png_voidp) NULL, (png_error_ptr) png_cexcept_error,
+                 (png_error_ptr) NULL, (png_voidp) NULL,
+                 (png_malloc_ptr) png_debug_malloc,
+                 (png_free_ptr) png_debug_free);
+#else
+               mng_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+                 (png_voidp) NULL, (png_error_ptr) png_cexcept_error,
+                 (png_error_ptr) NULL);
+#endif
+               if (mng_ptr == NULL)
+                  fprintf(STDERR, "pngcrush could not create mng_ptr");
+                  
+               if ((mng_out = FOPEN(mngname, "wb")) == NULL) {
+                  fprintf(STDERR, "Could not open output file %s\n",
+                          mngname);
+                  FCLOSE(fpin);
+                  exit(1);
+               }
+               number_of_open_files++;
+               png_init_io(mng_ptr, mng_out);
+               png_set_write_fn(mng_ptr, (png_voidp) mng_out,
+                               (png_rw_ptr) NULL,
+                               NULL);
+#endif
+
+            }
+
+            idat_length[0] = measure_idats(fpin);
+
+#ifdef PNGCRUSH_LOCO
+            if (new_mng) {
+                    png_destroy_write_struct(&mng_ptr, NULL);
+                    FCLOSE(mng_out);
+            }
+#endif
+
+            FCLOSE(fpin);
+
+
+            if (verbose > 0) {
+                
+                fprintf(STDERR, "   Recompressing %s\n", inname);
+                fprintf(STDERR,
+                  "   Total length of data found in IDAT chunks    = %8lu\n",
+                  (unsigned long)idat_length[0]);
+                fflush(STDERR);
+            }
+
+            if (idat_length[0] == 0)
+                continue;
+
+        } else
+            idat_length[0] = 1;
+
+        if (already_crushed) {
+            fprintf(STDERR, "   File %s has already been crushed.\n", inname);
+        }
+        if (image_is_immutable) {
+            fprintf(STDERR,
+              "   Image %s has a dSIG chunk and is immutable.\n", inname);
+        }
+        if (!already_crushed && !image_is_immutable) {
+#ifdef PNGCRUSH_COUNT_COLORS
+        reduce_to_gray = 0;
+        it_is_opaque = 0;
+        output_color_type = input_color_type;
+        if (do_color_count) {
+            if (force_output_color_type == 8 && (input_color_type == 2 ||
+                                                 (input_color_type == 3) ||
+                                                 input_color_type == 4
+                                                 || input_color_type == 6))
+            /* check for unused alpha channel or single transparent color */
+            {
+                int alpha_status;
+                P1( "Opening file %s for alpha check\n", inname);
+
+                if ((fpin = FOPEN(inname, "rb")) == NULL) {
+                    fprintf(STDERR, "Could not find file: %s\n", inname);
+                    continue;
+                }
+                number_of_open_files++;
+
+                alpha_status = count_colors(fpin);
+                if (num_rgba < 257) {
+                    P1("Finished counting colors. num_rgba=%d\n",
+                       num_rgba);
+                } else {
+                    P1("Finished counting colors. num_rgba is more than 256\n");
+                }
+                alpha_status = alpha_status;    /* silence compiler warning. */
+
+                FCLOSE(fpin);
+
+                if (it_is_opaque) {
+                    if (output_color_type == 4)
+                        output_color_type = 0;
+                    else if (output_color_type == 6)
+                        output_color_type = 2;
+                }
+                if (reduce_to_gray) {
+                    if (output_color_type == 2)
+                        output_color_type = 0;
+                    else if (output_color_type == 6)
+                        output_color_type = 4;
+                }
+            }
+#if 0 /* TO DO */
+            if (output_color_type == 0)
+                /* see if bit depth can be reduced */
+            {
+            }
+
+            if (input_color_type == 2)
+                /* check for 256 or fewer colors */
+            {
+                /* TO DO */
+            }
+
+            if (input_color_type == 3)
+                /* check for unused palette entries */
+            {
+                /* TO DO */
+            }
+#endif
+            if (force_output_color_type == 8
+                && input_color_type != output_color_type) {
+                P1("setting output color type to %d\n", output_color_type);
+                force_output_color_type = output_color_type;
+            }
+        }
+#else
+        if (do_color_count)
+            printf("   color counting (-cc option) is disabled.\n");
+#endif /* PNGCRUSH_COUNT_COLORS */
+
+        if (force_output_bit_depth != 0 &&
+            force_output_bit_depth != 1 &&
+            force_output_bit_depth != 2 &&
+            force_output_bit_depth != 4 &&
+            force_output_bit_depth != 8 &&
+            force_output_bit_depth != 16)
+          {
+            fprintf(STDERR, "\n  Ignoring invalid bit_depth: %d\n",
+              force_output_bit_depth);
+            force_output_bit_depth=0;
+          }
+        if (force_output_color_type != 8 &&
+            force_output_color_type != 0 &&
+            force_output_color_type != 2 &&
+            force_output_color_type != 3 &&
+            force_output_color_type != 4 &&
+            force_output_color_type != 6)
+          {
+            fprintf(STDERR, "\n  Ignoring invalid color_type: %d\n",
+              force_output_color_type);
+            force_output_color_type=8;
+          }
+        output_color_type = force_output_color_type;
+        output_bit_depth = force_output_bit_depth;
+
+        if (!methods_specified || try_method[0] == 0) {
+            for (i = 1; i <= DEFAULT_METHODS; i++)
+                try_method[i] = 0;
+            try_method[6] = try_method[0];
+        }
+
+        best_of_three = 1;
+
+        /* ////////////////////////////////////////////////////////////////////
+        ////////////////                                   ////////////////////
+        ////////////////  START OF MAIN LOOP OVER METHODS  ////////////////////
+        ////////////////                                   ////////////////////
+        //////////////////////////////////////////////////////////////////// */
+
+        /* MAX_METHODS is 200 */
+        P1("\n\nENTERING MAIN LOOP OVER %d METHODS\n", MAX_METHODS);
+        for (trial = 1; trial <= MAX_METHODS; trial++) {
+            idat_length[trial] = (png_uint_32) 0xffffffff;
+
+            /* this part of if-block is for final write-the-best-file
+               iteration */
+            if (trial == MAX_METHODS) {
+                png_uint_32 best_length;
+                int j;
+
+                /* check lengths */
+                best = 0;  /* i.e., input file */
+                best_length = (png_uint_32) 0xffffffff;
+                for (j = things_have_changed; j < MAX_METHODS; j++) {
+                    if (best_length > idat_length[j]) {
+                        best_length = idat_length[j];
+                        best = j;
+                    }
+                }
+
+                if (image_is_immutable
+                    || (idat_length[best] == idat_length[0]
+                    && things_have_changed == 0
+                    && idat_length[best] != idat_length[final_method]
+                    && nosave == 0))
+                {
+                    /* just copy input to output */
+
+                    P2("prepare to copy input to output\n");
+                    png_crush_pause();
+
+                    if ((fpin = FOPEN(inname, "rb")) == NULL) {
+                        fprintf(STDERR, "Could not find input file %s\n",
+                                inname);
+                        continue;
+                    }
+
+                    number_of_open_files++;
+                    if ((fpout = FOPEN(outname, "wb")) == NULL) {
+                        fprintf(STDERR, "Could not open output file %s\n",
+                                outname);
+                        FCLOSE(fpin);
+                        exit(1);
+                    }
+
+                    number_of_open_files++;
+                    P2("copying input to output... tc=%d ...",
+                       things_have_changed);
+
+                    for (;;) {
+                        png_size_t num_in;
+
+                        num_in = fread(buffer, 1, 1, fpin);
+                        if (!num_in)
+                            break;
+                        fwrite(buffer, 1, 1, fpout);
+                    }
+                    P2("copy complete.\n");
+                    png_crush_pause();
+                    FCLOSE(fpin);
+                    FCLOSE(fpout);
+                    setfiletype(outname);
+                    break;
+                }
+
+                if (idat_length[best] == idat_length[final_method]) {
+                    break;
+                } else {
+                    filter_type = fm[best];
+                    zlib_level = lv[best];
+                    if (zs[best] == 1)
+                        z_strategy = Z_FILTERED;
+                    else if (zs[best] == 2)
+                        z_strategy = Z_HUFFMAN_ONLY;
+#ifdef Z_RLE
+                    else if (zs[best] == 3)
+                        z_strategy = Z_RLE;
+#endif
+                    else /* if (zs[best] == 0) */
+                        z_strategy = Z_DEFAULT_STRATEGY;
+                }
+            } else {
+                if (trial > 2 && trial < 5 && idat_length[trial - 1]
+                    < idat_length[best_of_three])
+                    best_of_three = trial - 1;
+                if (try_method[trial]) {
+                    P2("skipping \"late\" trial %d\n", trial);
+                    continue;
+                }
+                if (!methods_specified && try_method[0]) {
+                    if ((trial == 4 || trial == 7) && best_of_three != 1) {
+                        P2("skipping \"early\" trial %d\n", trial);
+                        continue;
+                    }
+                    if ((trial == 5 || trial == 8) && best_of_three != 2) {
+                        P2("skipping \"early\" trial %d\n", trial);
+                        continue;
+                    }
+                    if ((trial == 6 || trial == 9 || trial == 10)
+                        && best_of_three != 3) {
+                        P2("skipping \"early\" trial %d\n", trial);
+                        continue;
+                    }
+                }
+                filter_type = fm[trial];
+                zlib_level = lv[trial];
+                if (zs[trial] == 1)
+                    z_strategy = Z_FILTERED;
+                else if (zs[trial] == 2)
+                    z_strategy = Z_HUFFMAN_ONLY;
+#ifdef Z_RLE
+                else if (zs[trial] == 3)
+                    z_strategy = Z_RLE;
+#endif
+                else /* if (zs[trial] == 0) */
+                    z_strategy = Z_DEFAULT_STRATEGY;
+                final_method = trial;
+                if (!nosave) {
+                    P2("\n\n------------------------------------------------\n"
+                       "Begin trial %d, filter %d, strategy %d, level %d\n",
+                       trial, filter_type, z_strategy, zlib_level);
+                }
+            }
+
+            P2("prepare to open files.\n");
+            png_crush_pause();
+
+            if ((fpin = FOPEN(inname, "rb")) == NULL) {
+                fprintf(STDERR, "Could not find input file %s\n", inname);
+                continue;
+            }
+            number_of_open_files++;
+            if (nosave == 0) {
+#ifndef __riscos
+                /* Can't sensibly check this on RISC OS without opening a file
+                   for update or output
+                 */
+                struct stat stat_in, stat_out;
+                if (first_trial && !nofilecheck
+                    && (stat(inname, &stat_in) == 0)
+                    && (stat(outname, &stat_out) == 0) &&
+#if defined(_MSC_VER) || defined(__MINGW32__)   /* maybe others? */
+                    /* MSVC++6.0 will erroneously return 0 for both files, so
+                       we simply check the size instead.  It is possible that
+                       we will erroneously reject the attempt when inputsize
+                       and outputsize are equal, for different files
+                     */
+                    (stat_in.st_size == stat_out.st_size) &&
+#else
+                    (stat_in.st_ino == stat_out.st_ino) &&
+#endif
+                    (stat_in.st_dev == stat_out.st_dev)) {
+                    fprintf(STDERR,
+                            "\n   Cannot overwrite input file %s\n",
+                            outname);
+                    P1("   st_ino=%d, st_size=%d\n\n",
+                       (int) stat_in.st_ino, (int) stat_in.st_size);
+                    FCLOSE(fpin);
+                    exit(1);
+                }
+#endif
+                if ((fpout = FOPEN(outname, "wb")) == NULL) {
+                    fprintf(STDERR, "Could not open output file %s\n",
+                            outname);
+                    FCLOSE(fpin);
+                    exit(1);
+                }
+
+                number_of_open_files++;
+            }
+
+            P2("files are opened.\n");
+            png_crush_pause();
+
+/* OK to ignore any warning about the address of exception__prev in "Try" */
+            Try {
+                png_uint_32 row_length;
+                P1( "Allocating read and write structures\n");
+#ifdef PNG_USER_MEM_SUPPORTED
+                read_ptr = png_create_read_struct_2(PNG_LIBPNG_VER_STRING,
+                  (png_voidp) NULL, (png_error_ptr) png_cexcept_error,
+                  (png_error_ptr) NULL, (png_voidp) NULL,
+                  (png_malloc_ptr) png_debug_malloc,
+                  (png_free_ptr) png_debug_free);
+#else
+                read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
+                  (png_voidp) NULL, (png_error_ptr) png_cexcept_error,
+                  (png_error_ptr) NULL);
+#endif
+                if (read_ptr == NULL)
+                    Throw "pngcrush could not create read_ptr";
+
+                if (nosave == 0) {
+#ifdef PNG_USER_MEM_SUPPORTED
+                    write_ptr = png_create_write_struct_2(PNG_LIBPNG_VER_STRING,
+                      (png_voidp) NULL, (png_error_ptr) png_cexcept_error,
+                      (png_error_ptr) NULL, (png_voidp) NULL,
+                      (png_malloc_ptr) png_debug_malloc,
+                      (png_free_ptr) png_debug_free);
+#else
+                    write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
+                      (png_voidp) NULL, (png_error_ptr) png_cexcept_error,
+                      (png_error_ptr) NULL);
+#endif
+                    if (write_ptr == NULL)
+                        Throw "pngcrush could not create write_ptr";
+
+                }
+                P1("Allocating read_info, write_info, end_info structures\n");
+                read_info_ptr = png_create_info_struct(read_ptr);
+                if (read_info_ptr == NULL)
+                    Throw "pngcrush could not create read_info_ptr";
+                end_info_ptr = png_create_info_struct(read_ptr);
+                if (end_info_ptr == NULL)
+                    Throw "pngcrush could not create end_info_ptr";
+                if (nosave == 0) {
+                    write_info_ptr = png_create_info_struct(write_ptr);
+                    if (write_info_ptr == NULL)
+                        Throw "pngcrush could not create write_info_ptr";
+                    write_end_info_ptr = png_create_info_struct(write_ptr);
+                    if (write_end_info_ptr == NULL)
+                        Throw
+                            "pngcrush could not create write_end_info_ptr";
+                }
+
+                P2("structures created.\n");
+                png_crush_pause();
+
+                P1( "Initializing input and output streams\n");
+#if !defined(PNG_NO_STDIO)
+                png_init_io(read_ptr, fpin);
+                if (nosave == 0)
+                    png_init_io(write_ptr, fpout);
+#else
+                png_set_read_fn(read_ptr, (png_voidp) fpin,
+                                (png_rw_ptr) NULL);
+                if (nosave == 0)
+                    png_set_write_fn(write_ptr, (png_voidp) fpout,
+                                     (png_rw_ptr) NULL,
+#if defined(PNG_WRITE_FLUSH_SUPPORTED)
+                                     png_default_flush);
+#else
+                                     NULL);
+#endif
+#endif
+
+                P2("io has been initialized.\n");
+                png_crush_pause();
+
+                /* We don't need to check CRC's because they were already
+                   checked in the png_measure_idat function */
+
+#ifdef PNG_CRC_QUIET_USE
+                png_set_crc_action(read_ptr, PNG_CRC_QUIET_USE,
+                                   PNG_CRC_QUIET_USE);
+#endif
+
+#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+                png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS,
+                                            (png_bytep) NULL, 0);
+#endif
+#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
+                if (nosave == 0) {
+                    if (found_any_chunk == 1)
+                    png_set_keep_unknown_chunks(write_ptr,
+                                                PNG_HANDLE_CHUNK_ALWAYS,
+                                                (png_bytep) "dSIG", 1);
+                    if (all_chunks_are_safe)
+                        png_set_keep_unknown_chunks(write_ptr,
+                                                    PNG_HANDLE_CHUNK_ALWAYS,
+                                                    (png_bytep) NULL, 0);
+                    else {
+#if !defined(PNG_cHRM_SUPPORTED) || !defined(PNG_hIST_SUPPORTED) || \
+    !defined(PNG_iCCP_SUPPORTED) || !defined(PNG_sCAL_SUPPORTED) || \
+    !defined(PNG_pCAL_SUPPORTED) || !defined(PNG_sPLT_SUPPORTED) || \
+    !defined(PNG_sTER_SUPPORTED) || !defined(PNG_tIME_SUPPORTED)
+                        png_byte chunk_name[5];
+                        chunk_name[4] = '\0';
+#endif
+
+                        if (keep_unknown_chunk("alla", argv) &&
+                            keep_unknown_chunk("allb", argv))
+                            png_set_keep_unknown_chunks(write_ptr,
+                                                    PNG_HANDLE_CHUNK_IF_SAFE,
+                                                    (png_bytep) NULL,
+                                                    0);
+                        else
+                            png_set_keep_unknown_chunks(write_ptr,
+                                                    PNG_HANDLE_CHUNK_NEVER,
+                                                    (png_bytep) NULL,
+                                                    0);
+
+#if !defined(PNG_cHRM_SUPPORTED)
+                        if (keep_unknown_chunk("cHRM", argv)) {
+                            png_save_uint_32(chunk_name, PNG_UINT_cHRM);
+                            png_set_keep_unknown_chunks(write_ptr,
+                                                    PNG_HANDLE_CHUNK_ALWAYS,
+                                                    chunk_name, 1);
+                        }
+#endif
+#if !defined(PNG_hIST_SUPPORTED)
+                        if (keep_unknown_chunk("hIST", argv)) {
+                            png_save_uint_32(chunk_name, PNG_UINT_hIST);
+                            png_set_keep_unknown_chunks(write_ptr,
+                                                    PNG_HANDLE_CHUNK_ALWAYS,
+                                                    chunk_name, 1);
+                        }
+#endif
+#if !defined(PNG_iCCP_SUPPORTED)
+                        if (keep_unknown_chunk("iCCP", argv)) {
+                            png_save_uint_32(chunk_name, PNG_UINT_iCCP);
+                            png_set_keep_unknown_chunks(write_ptr,
+                                                    PNG_HANDLE_CHUNK_ALWAYS,
+                                                    chunk_name, 1);
+                        }
+#endif
+#if !defined(PNG_sCAL_SUPPORTED)
+                        if (keep_unknown_chunk("sCAL", argv)) {
+                            png_save_uint_32(chunk_name, PNG_UINT_sCAL);
+                            png_set_keep_unknown_chunks(write_ptr,
+                                                    PNG_HANDLE_CHUNK_ALWAYS,
+                                                    chunk_name, 1);
+                        }
+#endif
+#if !defined(PNG_pCAL_SUPPORTED)
+                        if (keep_unknown_chunk("pCAL", argv)) {
+                            png_save_uint_32(chunk_name, PNG_UINT_pCAL);
+                            png_set_keep_unknown_chunks(write_ptr,
+                                                    PNG_HANDLE_CHUNK_ALWAYS,
+                                                    chunk_name, 1);
+                        }
+#endif
+#if !defined(PNG_sPLT_SUPPORTED)
+                        if (keep_unknown_chunk("sPLT", argv)) {
+                            png_save_uint_32(chunk_name, PNG_UINT_sPLT);
+                            png_set_keep_unknown_chunks(write_ptr,
+                                                    PNG_HANDLE_CHUNK_ALWAYS,
+                                                    chunk_name, 1);
+                        }
+#endif
+#if !defined(PNG_sTER_SUPPORTED)
+                        if (keep_unknown_chunk("sTER", argv)) {
+                            png_save_uint_32(chunk_name, PNG_UINT_sTER);
+                            png_set_keep_unknown_chunks(write_ptr,
+                                                    PNG_HANDLE_CHUNK_ALWAYS,
+                                                    chunk_name, 1);
+                        }
+#endif
+#if !defined(PNG_tIME_SUPPORTED)
+                        if (keep_unknown_chunk("tIME", argv)) {
+                            png_save_uint_32(chunk_name, PNG_UINT_tIME);
+                            png_set_keep_unknown_chunks(write_ptr,
+                                                    PNG_HANDLE_CHUNK_ALWAYS,
+                                                    chunk_name, 1);
+                        }
+#endif
+                    }
+                }
+#endif /* PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */
+
+                P1( "Reading info struct\n");
+                {
+#if defined(PNGCRUSH_LOCO)
+                    png_byte mng_signature[8] =
+                        { 138, 77, 78, 71, 13, 10, 26, 10 };
+#endif
+                    png_byte png_signature[8] =
+                        { 137, 80, 78, 71, 13, 10, 26, 10 };
+
+                    png_default_read_data(read_ptr, png_signature, 8);
+                    png_set_sig_bytes(read_ptr, 8);
+
+#if defined(PNGCRUSH_LOCO)
+                    if (!(int)
+                        (png_memcmp(mng_signature, png_signature, 8))) {
+                        /* Skip the MHDR */
+                        png_permit_mng_features(read_ptr,
+                                                PNG_FLAG_MNG_FILTER_64);
+                        png_skip_chunk(read_ptr);
+                        input_format = 1;
+                    } else
+#endif
+                        if (png_sig_cmp(png_signature, 0, 8)) {
+                            if (png_sig_cmp(png_signature, 0, 4))
+                                png_error(read_ptr, "Not a PNG file!");
+                        else
+                            png_error(read_ptr,
+                                "PNG file corrupted by ASCII conversion");
+                    }
+                    if(fix && found_CgBI)
+                    {
+                        /* Skip the CgBI chunk */
+
+                        png_skip_chunk(read_ptr);
+
+                        /* iCCP and zTXt are probably unreadable
+                         * because of the nonstandard deflate */
+
+                        png_set_keep_unknown_chunks(read_ptr,
+                            PNG_HANDLE_CHUNK_NEVER,
+                            (png_bytep)"iCCP", 1);
+                        png_set_keep_unknown_chunks(read_ptr,
+                            PNG_HANDLE_CHUNK_NEVER,
+                            (png_bytep)"zTXt", 1);
+                    }
+                }
+
+                png_read_info(read_ptr, read_info_ptr);
+
+                /* { GRR added for quick %-navigation (1) */
+
+                /* Start of chunk-copying/removal code, in order:
+                 *  - IHDR
+                 *  - bKGD
+                 *  - cHRM
+                 *  - gAMA
+                 *  - sRGB
+                 *  - iCCP
+                 *  - oFFs
+                 *  - pCAL
+                 *  - pHYs
+                 *  - hIST
+                 *  - tRNS
+                 *  - PLTE
+                 *  - sBIT
+                 *  - sCAL
+                 *  - sPLT
+                 *  - sTER
+                 *  - tEXt/zTXt/iTXt
+                 *  - tIME
+                 *  - unknown chunks
+                 */
+                {
+                    int interlace_method, compression_method,
+                        filter_method;
+
+                    P1( "Transferring info struct\n");
+
+                    if (png_get_IHDR
+                        (read_ptr, read_info_ptr, &width, &height,
+                         &bit_depth, &color_type, &interlace_method,
+                         &compression_method, &filter_method)) {
+                        int need_expand = 0;
+                        input_color_type = color_type;
+                        input_bit_depth = bit_depth;
+
+                        if (output_color_type > 7) {
+                            output_color_type = input_color_type;
+                        }
+
+                        if (verbose > 1 && first_trial) {
+                            fprintf(STDERR, "   IHDR chunk data:\n");
+                            fprintf(STDERR,
+                                    "      Width=%lu, height=%lu\n",
+                                    (unsigned long)width,
+                                    (unsigned long)height);
+                            fprintf(STDERR, "      Bit depth =%d\n",
+                                    bit_depth);
+                            fprintf(STDERR, "      Color type=%d\n",
+                                    color_type);
+                            if (output_color_type != color_type)
+                                fprintf(STDERR,
+                                        "      Output color type=%d\n",
+                                        output_color_type);
+                            fprintf(STDERR, "      Interlace =%d\n",
+                                    interlace_method);
+                        }
+
+#ifndef PNG_WRITE_PACK_SUPPORTED
+                        if (output_bit_depth == 0)
+#else
+                        if (force_output_bit_depth == 0)
+#endif
+                        {
+                            output_bit_depth = input_bit_depth;
+                        }
+                        if ((output_color_type != 3
+                             || output_bit_depth > 8)
+                            && output_bit_depth >= 8
+                            && output_bit_depth != input_bit_depth)
+                            need_expand = 1;
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)
+                        if ((color_type == 2 || color_type == 6
+                                             || color_type == 3) &&
+                            (output_color_type == 0 || output_color_type == 4))
+                        {
+                            if (verbose > 0 && first_trial) {
+#ifdef PNGCRUSH_COUNT_COLORS
+                                if (reduce_to_gray)
+                                    fprintf(STDERR, "   Reducing all-gray "
+                                      "truecolor image to grayscale.\n");
+                                else
+#endif
+                                    fprintf(STDERR, "   Reducing truecolor "
+                                      "image to grayscale.\n");
+                            }
+#ifdef PNG_FIXED_POINT_SUPPORTED
+                            png_set_rgb_to_gray_fixed(read_ptr, 1, -1, -1);
+#else
+                            png_set_rgb_to_gray(read_ptr, 1, 0., 0.);
+#endif
+                            if (output_bit_depth < 8)
+                                output_bit_depth = 8;
+                            if (color_type == 3)
+                                need_expand = 1;
+                        }
+#endif
+
+                        if (color_type != 3 && output_color_type == 3) {
+                            printf("  Cannot change to indexed color "
+                              "(color_type 3)\n");
+                            output_color_type = input_color_type;
+                        }
+
+                        if ((color_type == 0 || color_type == 4) &&
+                            (output_color_type == 2
+                             || output_color_type == 6)) {
+                            png_set_gray_to_rgb(read_ptr);
+                        }
+
+                        if ((color_type == 4 || color_type == 6) &&
+                            (output_color_type != 4
+                             && output_color_type != 6)) {
+                            if (verbose > 0 && first_trial) {
+#ifdef PNGCRUSH_COUNT_COLORS
+                                if (it_is_opaque)
+                                    fprintf(STDERR,
+                                      "   Stripping opaque alpha channel.\n");
+                                else
+#endif
+                                    fprintf(STDERR,
+                                      "   Stripping existing alpha channel.\n");
+                            }
+#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED
+                            png_set_strip_alpha(read_ptr);
+#endif
+                        }
+
+                        if ((output_color_type == 4
+                             || output_color_type == 6) && (color_type != 4
+                                                            && color_type
+                                                            != 6)) {
+                            if (verbose > 0 && first_trial)
+                                fprintf(STDERR,
+                                  "   Adding an opaque alpha channel.\n");
+#ifdef PNG_READ_FILLER_SUPPORTED
+                            png_set_filler(read_ptr, (png_uint_32) 65535L,
+                                           PNG_FILLER_AFTER);
+#endif
+                            need_expand = 1;
+                        }
+
+                        if (output_color_type && output_color_type != 3 &&
+                            output_bit_depth < 8)
+                            output_bit_depth = 8;
+
+                        if ((output_color_type == 2
+                             || output_color_type == 6)
+                            && color_type == 3) {
+                            if (verbose > 0 && first_trial)
+                                fprintf(STDERR,
+                                  "   Expanding indexed color file.\n");
+                            need_expand = 1;
+                        }
+#ifdef PNG_READ_EXPAND_SUPPORTED
+                        if (need_expand == 1)
+                            png_set_expand(read_ptr);
+#endif
+
+#ifdef PNG_READ_PACK_SUPPORTED
+                        if (input_bit_depth < 8) {
+                            png_set_packing(read_ptr);
+                        }
+                        if (output_color_type == 0 && output_bit_depth < 8) {
+                            png_color_8 true_bits;
+                            true_bits.gray = (png_byte) (output_bit_depth);
+                            png_set_shift(read_ptr, &true_bits);
+                        }
+#endif
+
+                        if (verbose > 1)
+                            fprintf(STDERR, "   Setting IHDR\n");
+
+#if defined(PNGCRUSH_LOCO)
+                        output_format = 0;
+                        if (do_loco) {
+                            if (output_color_type == 2
+                                || output_color_type == 6) {
+                                output_format = 1;
+                                filter_method = 64;
+                                png_permit_mng_features(write_ptr,
+                                                        PNG_FLAG_MNG_FILTER_64);
+                            }
+                        } else
+                            filter_method = 0;
+                        if (input_format != output_format)
+                            things_have_changed = 1;
+#endif
+
+                        png_set_IHDR(write_ptr, write_info_ptr, width,
+                                     height, output_bit_depth,
+                                     output_color_type, interlace_method,
+                                     compression_method, filter_method);
+
+                        if (output_color_type != input_color_type)
+                            things_have_changed = 1;
+
+                    }
+                }
+
+#if defined(PNG_READ_bKGD_SUPPORTED) && defined(PNG_WRITE_bKGD_SUPPORTED)
+                {
+                    png_color_16p background;
+                    if (!have_bkgd
+                        && png_get_bKGD(read_ptr, read_info_ptr,
+                                        &background)) {
+                        if (keep_chunk("bKGD", argv)) {
+                            if ((input_color_type == 2
+                                 || input_color_type == 6)
+                                && (output_color_type == 0
+                                    || output_color_type == 4))
+                                background->gray = background->green;
+                            png_set_bKGD(write_ptr, write_info_ptr,
+                                         background);
+                        }
+                    }
+                    if (have_bkgd) {
+                        /* If we are reducing an RGB image to grayscale, but
+                           the background color isn't gray, the green channel
+                           is written.  That's not spec-compliant.  We should
+                           really check for a non-gray bKGD and refuse to do
+                           the reduction if one is present. */
+                        png_color_16 backgd;
+                        png_color_16p backgrnd = &backgd;
+                        backgrnd->red = bkgd_red;
+                        backgrnd->green = bkgd_green;
+                        backgrnd->blue = bkgd_blue;
+                        backgrnd->gray = backgrnd->green;
+                        png_set_bKGD(write_ptr, write_info_ptr,
+                                     backgrnd);
+                    }
+                }
+#endif /* defined(PNG_READ_bKGD_SUPPORTED)&&defined(PNG_WRITE_bKGD_SUPPORTED) */
+#if defined(PNG_READ_cHRM_SUPPORTED) && defined(PNG_WRITE_cHRM_SUPPORTED)
+#ifdef PNG_FIXED_POINT_SUPPORTED
+                {
+                    png_fixed_point white_x, white_y, red_x, red_y,
+                        green_x, green_y, blue_x, blue_y;
+
+                    if (found_cHRM && png_get_cHRM_fixed
+                        (read_ptr, read_info_ptr, &white_x, &white_y,
+                         &red_x, &red_y, &green_x, &green_y, &blue_x,
+                         &blue_y)) {
+                        if (keep_chunk("cHRM", argv)) {
+                                png_set_cHRM_fixed(write_ptr,
+                                                   write_info_ptr, white_x,
+                                                   white_y, red_x, red_y,
+                                                   green_x, green_y,
+                                                   blue_x, blue_y);
+                        }
+                    }
+                }
+#else
+                {
+                    double white_x, white_y, red_x, red_y, green_x,
+                        green_y, blue_x, blue_y;
+
+                    if (png_get_cHRM
+                        (read_ptr, read_info_ptr, &white_x, &white_y,
+                         &red_x, &red_y, &green_x, &green_y, &blue_x,
+                         &blue_y)) {
+                        if (keep_chunk("cHRM", argv)) {
+                                png_set_cHRM(write_ptr, write_info_ptr,
+                                             white_x, white_y, red_x,
+                                             red_y, green_x, green_y,
+                                             blue_x, blue_y);
+                        }
+                    }
+                }
+#endif /* ?PNG_FIXED_POINT_SUPPORTED */
+#endif /* PNG_READ_cHRM_SUPPORTED) && defined(PNG_WRITE_cHRM_SUPPORTED */
+
+#if defined(PNG_READ_gAMA_SUPPORTED) && defined(PNG_WRITE_gAMA_SUPPORTED)
+                {
+                    if (force_specified_gamma) {
+                        if (first_trial) {
+                            things_have_changed = 1;
+                            if (verbose > 0)
+                                fprintf(STDERR, "   Inserting gAMA chunk with "
+#ifdef PNG_FIXED_POINT_SUPPORTED
+                                  "gamma=(%d/100000)\n",
+#else
+                                  "gamma=%f\n",
+#endif
+                                  force_specified_gamma);
+                        }
+#ifdef PNG_FIXED_POINT_SUPPORTED
+                        png_set_gAMA_fixed(write_ptr, write_info_ptr,
+                                           (png_fixed_point)
+                                           force_specified_gamma);
+                        file_gamma =
+                            (png_fixed_point) force_specified_gamma;
+#else
+                        png_set_gAMA(write_ptr, write_info_ptr,
+                                     force_specified_gamma);
+                        file_gamma = force_specified_gamma;
+#endif
+                    }
+#ifdef PNG_FIXED_POINT_SUPPORTED
+                    else if (found_gAMA && png_get_gAMA_fixed
+                             (read_ptr, read_info_ptr, &file_gamma))
+#else
+                    else if (found_gAMA && png_get_gAMA
+                             (read_ptr, read_info_ptr, &file_gamma))
+#endif
+                    {
+                        if (keep_chunk("gAMA", argv)) {
+                            if (image_specified_gamma)
+                                file_gamma = image_specified_gamma;
+                            if (verbose > 1 && first_trial)
+#ifdef PNG_FIXED_POINT_SUPPORTED
+                                fprintf(STDERR, "   gamma=(%d/100000)\n",
+                                        (int) file_gamma);
+                            if (double_gamma)
+                                file_gamma += file_gamma;
+                            png_set_gAMA_fixed(write_ptr, write_info_ptr,
+                                               file_gamma);
+#else
+                                fprintf(STDERR, "   gamma=%f\n",
+                                        file_gamma);
+                            if (double_gamma)
+                                file_gamma += file_gamma;
+                            png_set_gAMA(write_ptr, write_info_ptr,
+                                         file_gamma);
+#endif
+                        }
+                    } else if (specified_gamma) {
+                        if (first_trial) {
+                            things_have_changed = 1;
+                            if (verbose > 0)
+                                fprintf(STDERR, "   Inserting gAMA chunk with "
+#ifdef PNG_FIXED_POINT_SUPPORTED
+                                  "gamma=(%d/100000)\n",
+#else
+                                  "gamma=%f\n",
+#endif
+                                  specified_gamma);
+                        }
+#ifdef PNG_FIXED_POINT_SUPPORTED
+                        png_set_gAMA_fixed(write_ptr, write_info_ptr,
+                                           specified_gamma);
+                        file_gamma = (png_fixed_point) specified_gamma;
+#else
+                        png_set_gAMA(write_ptr, write_info_ptr,
+                                     specified_gamma);
+                        file_gamma = specified_gamma;
+#endif
+                    }
+                }
+#endif /* defined(PNG_READ_gAMA_SUPPORTED)&&defined(PNG_WRITE_gAMA_SUPPORTED) */
+
+#if defined(PNG_READ_sRGB_SUPPORTED) && defined(PNG_WRITE_sRGB_SUPPORTED)
+                {
+                    int file_intent;
+
+                    if (png_get_sRGB
+                        (read_ptr, read_info_ptr, &file_intent)) {
+                        if (keep_chunk("sRGB", argv)) {
+                            png_set_sRGB(write_ptr, write_info_ptr,
+                                         file_intent);
+                            intent = file_intent;
+                        }
+                    } else if (intent >= 0) {
+#ifdef PNG_gAMA_SUPPORTED
+#ifdef PNG_FIXED_POINT_SUPPORTED
+                        if (file_gamma >= 45000L && file_gamma <= 46000L)
+#else
+                        if (file_gamma >= 0.45000 && file_gamma <= 0.46000)
+#endif
+                        {
+                            things_have_changed = 1;
+                            if (first_trial)
+                                fprintf(STDERR,
+                                  "   Inserting sRGB chunk with intent=%d\n",
+                                  intent);
+                            png_set_sRGB(write_ptr, write_info_ptr,
+                                         intent);
+                        } else if (file_gamma != 0) {
+                            if (first_trial) {
+                                fprintf(STDERR, "   Ignoring sRGB request; "
+#ifdef PNG_FIXED_POINT_SUPPORTED
+                                  "gamma=(%lu/100000)"
+#else
+                                  "gamma=%f"
+#endif
+                                  " is not approx. 0.455\n",
+                                  (unsigned long)file_gamma);
+                            }
+                        }
+#endif /* PNG_gAMA_SUPPORTED */
+                    }
+                }
+#endif /* defined(PNG_READ_sRGB_SUPPORTED)&&defined(PNG_WRITE_sRGB_SUPPORTED) */
+
+#if defined(PNG_READ_iCCP_SUPPORTED) && defined(PNG_WRITE_iCCP_SUPPORTED)
+                if (intent < 0) {  /* ignore iCCP if sRGB is being written */
+                    png_charp name;
+                    png_charp profile;
+                    png_uint_32 proflen;
+                    int compression_method;
+
+                    if (png_get_iCCP
+                        (read_ptr, read_info_ptr, &name,
+                         &compression_method, &profile, &proflen)) {
+                        P1("Got iCCP chunk, proflen=%lu\n",
+                            (unsigned long)proflen);
+                        if (iccp_length)
+                            P0("Will not replace existing iCCP chunk.\n");
+                        if (keep_chunk("iCCP", argv))
+                            png_set_iCCP(write_ptr, write_info_ptr, name,
+                                         compression_method, profile,
+                                         proflen);
+
+                    }
+#ifdef PNG_iCCP_SUPPORTED
+                    else if (iccp_length) {
+                        png_set_iCCP(write_ptr, write_info_ptr, iccp_name,
+                                     0, iccp_text, iccp_length);
+                        P1("Wrote iCCP chunk, proflen=%d\n", iccp_length);
+                    }
+#endif
+
+                }
+#endif /* defined(PNG_READ_iCCP_SUPPORTED)&&defined(PNG_WRITE_iCCP_SUPPORTED) */
+
+#if defined(PNG_READ_oFFs_SUPPORTED) && defined(PNG_WRITE_oFFs_SUPPORTED)
+                {
+                    png_int_32 offset_x, offset_y;
+                    int unit_type;
+
+                    if (png_get_oFFs
+                        (read_ptr, read_info_ptr, &offset_x, &offset_y,
+                         &unit_type)) {
+                        if (offset_x == 0 && offset_y == 0) {
+                            if (verbose > 0 && first_trial)
+                                fprintf(STDERR,
+                                  "   Deleting useless oFFs 0 0 chunk\n");
+                        } else {
+                            if (keep_chunk("oFFs", argv))
+                                png_set_oFFs(write_ptr, write_info_ptr,
+                                             offset_x, offset_y,
+                                             unit_type);
+                        }
+                    }
+                }
+#endif
+
+#if defined(PNG_READ_pCAL_SUPPORTED) && defined(PNG_WRITE_pCAL_SUPPORTED)
+                {
+                    png_charp purpose, units;
+                    png_charpp params;
+                    png_int_32 X0, X1;
+                    int type, nparams;
+
+                    if (png_get_pCAL
+                        (read_ptr, read_info_ptr, &purpose, &X0, &X1,
+                         &type, &nparams, &units, ¶ms)) {
+                        if (keep_chunk("pCAL", argv))
+                            png_set_pCAL(write_ptr, write_info_ptr,
+                                         purpose, X0, X1, type, nparams,
+                                         units, params);
+                    }
+                }
+#endif
+
+#if defined(PNG_READ_pHYs_SUPPORTED) && defined(PNG_WRITE_pHYs_SUPPORTED)
+                {
+                    png_uint_32 res_x, res_y;
+                    int unit_type;
+
+                    if (resolution == 0) {
+                        if (png_get_pHYs
+                            (read_ptr, read_info_ptr, &res_x, &res_y,
+                             &unit_type)) {
+                            if (res_x == 0 && res_y == 0) {
+                                if (verbose > 0 && first_trial)
+                                    fprintf(STDERR,
+                                      "   Deleting useless pHYs 0 0 chunk\n");
+                            } else {
+                                if (keep_chunk("pHYs", argv))
+                                    png_set_pHYs(write_ptr, write_info_ptr,
+                                                 res_x, res_y, unit_type);
+                            }
+                        }
+                    } else {
+                        unit_type = 1;
+                        res_x = res_y =
+                            (png_uint_32) ((resolution / .0254 + 0.5));
+                        png_set_pHYs(write_ptr, write_info_ptr, res_x,
+                                     res_y, unit_type);
+                        if (verbose > 0 && first_trial)
+                            fprintf(STDERR, "   Added pHYs %lu %lu 1 chunk\n",
+                            (unsigned long)res_x, 
+                            (unsigned long)res_y);
+                    }
+                }
+#endif
+
+#if defined(PNG_READ_hIST_SUPPORTED) && defined(PNG_WRITE_hIST_SUPPORTED)
+                {
+                    png_uint_16p hist;
+
+                    if (png_get_hIST(read_ptr, read_info_ptr, &hist)) {
+                        if (keep_chunk("hIST", argv))
+                            png_set_hIST(write_ptr, write_info_ptr, hist);
+                    }
+                }
+#endif
+
+#if defined(PNG_READ_tRNS_SUPPORTED) && defined(PNG_WRITE_tRNS_SUPPORTED)
+                {
+                    png_bytep trans;
+                    int num_trans;
+                    png_color_16p trans_values;
+
+                    if (png_get_tRNS
+                        (read_ptr, read_info_ptr, &trans, &num_trans,
+                         &trans_values)) {
+                        if (verbose > 1)
+                            fprintf(STDERR,
+                              "  Found tRNS chunk in input file.\n");
+                        if (have_trns == 1) {
+                            P0("  Will not overwrite existing tRNS chunk.\n");
+                        }
+                        if (keep_chunk("tRNS", argv)) {
+                            int last_nonmax = -1;
+                            trns_red = trans_values->red;
+                            trns_green = trans_values->green;
+                            trns_blue = trans_values->blue;
+                            trns_gray = trans_values->gray;
+                            if (output_color_type == 3) {
+                                for (ia = 0; ia < num_trans; ia++)
+                                    trns_array[ia] = trans[ia];
+                                for (; ia < 256; ia++)
+                                    trns_array[ia] = 255;
+                                for (ia = 0; ia < 256; ia++) {
+                                    if (trns_array[ia] != 255)
+                                        last_nonmax = ia;
+                                }
+                                if (first_trial && verbose > 0) {
+                                    if (last_nonmax < 0)
+                                        fprintf(STDERR, "   Deleting "
+                                          "all-opaque tRNS chunk.\n");
+                                    else if (last_nonmax + 1 < num_trans)
+                                        fprintf(STDERR,
+                                          "   Truncating trailing opaque "
+                                          "entries from tRNS chunk.\n");
+                                }
+                                num_trans = last_nonmax + 1;
+                            }
+                            if (verbose > 1)
+                                fprintf(STDERR,
+                                  "   png_set_tRNS, num_trans=%d\n",
+                                  num_trans);
+                            if (output_color_type != 3 || num_trans)
+                                png_set_tRNS(write_ptr, write_info_ptr,
+                                             trans, num_trans,
+                                             trans_values);
+                        }
+                    } else if (have_trns == 1) {
+                        /* will not overwrite existing trns data */
+                        png_color_16 trans_data;
+                        png_byte index_data = (png_byte) trns_index;
+                        num_trans = index_data + 1;
+                        if (verbose > 1)
+                            fprintf(STDERR, "Have_tRNS, num_trans=%d\n",
+                                    num_trans);
+                        if (output_color_type == 3) {
+                            trans_values = NULL;
+                            for (ia = 0; ia < num_trans; ia++)
+                                trns_array[ia] = trans_in[ia];
+                            for (; ia < 256; ia++)
+                                trns_array[ia] = 255;
+                        } else {
+                            for (ia = 0; ia < 256; ia++)
+                                trns_array[ia] = 255;
+                            trns_array[index_data] = 0;
+
+                            trans_data.index = index_data;
+                            trans_data.red = trns_red;
+                            trans_data.green = trns_green;
+                            trans_data.blue = trns_blue;
+                            trans_data.gray = trns_gray;
+                            trans_values = &trans_data;
+                        }
+
+                        P0("  Adding a tRNS chunk\n");
+                        png_set_tRNS(write_ptr, write_info_ptr, trns_array,
+                                     num_trans, trans_values);
+
+                        things_have_changed = 1;
+                    } else {
+                        for (ia = 0; ia < 256; ia++)
+                            trns_array[ia] = 255;
+                    }
+                    if (verbose > 1 && first_trial) {
+                        int last = -1;
+                        for (i = 0; ia < num_palette; ia++)
+                            if (trns_array[ia] != 255)
+                                last = ia;
+                        if (last >= 0) {
+                            fprintf(STDERR, "   Transparency:\n");
+                            if (output_color_type == 3)
+                                for (i = 0; ia < num_palette; ia++)
+                                    fprintf(STDERR, "      %4d %4d\n", ia,
+                                            trns_array[ia]);
+                            else if (output_color_type == 0)
+                                fprintf(STDERR, "      %d\n", trns_gray);
+                            else if (output_color_type == 2)
+                                fprintf(STDERR, "      %d %d %d\n",
+                                        trns_red, trns_green, trns_blue);
+                        }
+                    }
+                }
+#endif /* defined(PNG_READ_tRNS_SUPPORTED)&&defined(PNG_WRITE_tRNS_SUPPORTED) */
+
+                if (png_get_PLTE
+                    (read_ptr, read_info_ptr, &palette, &num_palette))
+                {
+                    if (plte_len > 0)
+                        num_palette = plte_len;
+                    if (do_pplt) {
+                        printf("PPLT: %s\n", pplt_string);
+                        printf("Sorry, PPLT is not implemented yet.\n");
+                    }
+                    if (output_color_type == 3)
+                        png_set_PLTE(write_ptr, write_info_ptr, palette,
+                                     num_palette);
+                    else if (keep_chunk("PLTE", argv))
+                        png_set_PLTE(write_ptr, write_info_ptr, palette,
+                                     num_palette);
+                    if (verbose > 1 && first_trial) {
+                        png_colorp p = palette;
+                        fprintf(STDERR, "   Palette:\n");
+                        fprintf(STDERR,
+                          "      I    R    G    B ( color )    A\n");
+                        for (i = 0; i < num_palette; i++) {
+                            fprintf(STDERR,
+                              "   %4d %4d %4d %4d (#%2.2x%2.2x%2.2x) %4d\n",
+                              i, p->red, p->green, p->blue, p->red,
+                              p->green, p->blue, trns_array[i]);
+                            p++;
+                        }
+                    }
+                }
+
+
+#if defined(PNG_READ_sBIT_SUPPORTED) && defined(PNG_WRITE_sBIT_SUPPORTED)
+                {
+                    png_color_8p sig_bit;
+
+                    /* If we are reducing a truecolor PNG to grayscale, and the
+                     * RGB sBIT values aren't identical, we'll lose sBIT info.
+                     */
+                    if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit)) {
+                        if (keep_chunk("sBIT", argv)) {
+                            if ((input_color_type == 0
+                                 || input_color_type == 4)
+                                && (output_color_type == 2
+                                    || output_color_type == 6
+                                    || output_color_type == 3))
+                                sig_bit->red = sig_bit->green =
+                                    sig_bit->blue = sig_bit->gray;
+                            if ((input_color_type == 2
+                                 || input_color_type == 6
+                                 || output_color_type == 3)
+                                && (output_color_type == 0
+                                    || output_color_type == 4))
+                                sig_bit->gray = sig_bit->green;
+
+                            if ((input_color_type == 0
+                                 || input_color_type == 2)
+                                && (output_color_type == 4
+                                    || output_color_type == 6))
+                                sig_bit->alpha = 1;
+
+                            png_set_sBIT(write_ptr, write_info_ptr,
+                                         sig_bit);
+                        }
+                    }
+                }
+#endif /* defined(PNG_READ_sBIT_SUPPORTED)&&defined(PNG_WRITE_sBIT_SUPPORTED) */
+
+#if defined(PNG_sCAL_SUPPORTED)
+#ifdef PNG_FLOATING_POINT_SUPPORTED
+                {
+                    int unit;
+                    double scal_width, scal_height;
+
+                    if (png_get_sCAL
+                        (read_ptr, read_info_ptr, &unit, &scal_width,
+                         &scal_height)) {
+                        png_set_sCAL(write_ptr, write_info_ptr, unit,
+                                     scal_width, scal_height);
+                    }
+                }
+#else
+#ifdef PNG_FIXED_POINT_SUPPORTED
+                {
+                    int unit;
+                    png_charp scal_width, scal_height;
+
+                    if (png_get_sCAL_s
+                        (read_ptr, read_info_ptr, &unit, &scal_width,
+                         &scal_height)) {
+                        if (keep_chunk("sCAL", argv))
+                            png_set_sCAL_s(write_ptr, write_info_ptr, unit,
+                                           scal_width, scal_height);
+                    }
+                }
+#endif
+#endif /* PNG_FLOATING_POINT_SUPPORTED */
+#endif /* ?PNG_sCAL_SUPPORTED */
+
+#if defined(PNG_sPLT_SUPPORTED)
+                {
+                    png_sPLT_tp entries;
+                    int num_entries;
+
+                    num_entries =
+                        (int) png_get_sPLT(read_ptr, read_info_ptr,
+                                           &entries);
+                    if (num_entries) {
+                        if (keep_chunk("sPLT", argv))
+                            png_set_sPLT(write_ptr, write_info_ptr,
+                                         entries, num_entries);
+                        png_free_data(read_ptr, read_info_ptr,
+                                      PNG_FREE_SPLT, num_entries);
+                    }
+                }
+#endif
+
+#if defined(PNG_TEXT_SUPPORTED)
+                {
+                    png_textp text_ptr;
+                    int num_text = 0;
+
+                    if (png_get_text
+                        (read_ptr, read_info_ptr, &text_ptr, &num_text) > 0
+                        || text_inputs) {
+                        int ntext;
+                        P1( "Handling %d tEXt/zTXt chunks\n",
+                                   num_text);
+
+                        if (verbose > 1 && first_trial && num_text > 0) {
+                            for (ntext = 0; ntext < num_text; ntext++) {
+                                fprintf(STDERR, "%d  %s", ntext,
+                                        text_ptr[ntext].key);
+                                if (text_ptr[ntext].text_length)
+                                    fprintf(STDERR, ": %s\n",
+                                            text_ptr[ntext].text);
+#ifdef PNG_iTXt_SUPPORTED
+                                else if (text_ptr[ntext].itxt_length) {
+                                    fprintf(STDERR, " (%s: %s): \n",
+                                            text_ptr[ntext].lang,
+                                            text_ptr[ntext].lang_key);
+                                    fprintf(STDERR, "%s\n",
+                                            text_ptr[ntext].text);
+                                }
+#endif
+                                else
+                                    fprintf(STDERR, "\n");
+                            }
+                        }
+
+                        if (num_text > 0) {
+                            if (keep_chunk("text", argv)) {
+                                int num_to_write = num_text;
+                                for (ntext = 0; ntext < num_text; ntext++) {
+                                    if (first_trial)
+                                        P2("Text chunk before IDAT, "
+                                          "compression=%d\n",
+                                          text_ptr[ntext].compression);
+                                    if (text_ptr[ntext].compression ==
+                                        PNG_TEXT_COMPRESSION_NONE) {
+                                        if (!keep_chunk("tEXt", argv)) {
+                                            text_ptr[ntext].key[0] = '\0';
+                                            num_to_write--;
+                                        }
+                                    }
+                                    if (text_ptr[ntext].compression ==
+                                        PNG_TEXT_COMPRESSION_zTXt) {
+                                        if (!keep_chunk("zTXt", argv)) {
+                                            text_ptr[ntext].key[0] = '\0';
+                                            num_to_write--;
+                                        }
+                                    }
+#ifdef PNG_iTXt_SUPPORTED
+                                    if (text_ptr[ntext].compression ==
+                                        PNG_ITXT_COMPRESSION_NONE
+                                        || text_ptr[ntext].compression ==
+                                        PNG_ITXT_COMPRESSION_zTXt) {
+                                        if (!keep_chunk("iTXt", argv)) {
+                                            text_ptr[ntext].key[0] = '\0';
+                                            num_to_write--;
+                                        }
+                                    }
+#endif
+                                }
+                                if (num_to_write > 0)
+                                    png_set_text(write_ptr, write_info_ptr,
+                                                 text_ptr, num_text);
+                            }
+                        }
+                        for (ntext = 0; ntext < text_inputs; ntext++) {
+                            if (text_where[ntext] == 1) {
+                                png_textp added_text;
+                                added_text = (png_textp) png_malloc(write_ptr,
+                                               (png_uint_32) sizeof(png_text));
+                                added_text[0].key = &text_keyword[ntext * 80];
+#ifdef PNG_iTXt_SUPPORTED
+                                added_text[0].lang = &text_lang[ntext * 80];
+                                added_text[0].lang_key =
+                                    &text_lang_key[ntext * 80];
+#endif
+                                added_text[0].text = &text_text[ntext * 2048];
+                                added_text[0].compression =
+                                    text_compression[ntext];
+                                png_set_text(write_ptr, write_info_ptr,
+                                             added_text, 1);
+                                if (added_text[0].compression < 0)
+                                    printf("   Added a tEXt chunk.\n");
+                                else if (added_text[0].compression == 0)
+                                    printf("   Added a zTXt chunk.\n");
+#ifdef PNG_iTXt_SUPPORTED
+                                else
+                                    printf("   Added a%scompressed iTXt chunk"
+                                      ".\n", (added_text[0].compression == 1)?
+                                      "n un" : " ");
+#endif
+                                png_free(write_ptr, added_text);
+                                added_text = (png_textp) NULL;
+                            }
+                        }
+                    }
+                }
+#endif /* defined(PNG_TEXT_SUPPORTED) */
+
+#if defined(PNG_READ_tIME_SUPPORTED) && defined(PNG_WRITE_tIME_SUPPORTED)
+                {
+                    png_timep mod_time;
+
+                    if (png_get_tIME(read_ptr, read_info_ptr, &mod_time)) {
+                        if (keep_chunk("tIME", argv))
+                            png_set_tIME(write_ptr, write_info_ptr, mod_time);
+                    }
+                }
+#endif
+
+#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED
+                /* This section handles pCAL and tIME (at least, in default
+                 * build), gIFx/gIFg/gIFt, private Fireworks chunks, etc. */
+                {
+                    png_unknown_chunkp unknowns;   /* allocated by libpng */
+                    int num_unknowns;
+
+                    if (nosave == 0 && ster_mode >= 0) {
+                      /* Add sTER chunk */
+                      png_unknown_chunkp ster;
+                      P1("Handling sTER as unknown chunk %d\n", i);
+                      ster = (png_unknown_chunk*)png_malloc(read_ptr,
+                          (png_uint_32) sizeof(png_unknown_chunk));
+                      png_memcpy((char *)ster[0].name, "sTER",5);
+                      ster[0].size = 1;
+                      ster[0].data = (png_byte*)png_malloc(read_ptr, 1);
+                      ster[0].data[0] = (png_byte)ster_mode;
+                      png_set_unknown_chunks(read_ptr, read_info_ptr,
+                       ster, 1);
+                      png_free(read_ptr,ster[0].data);
+                      png_free(read_ptr,ster);
+                    }
+
+                    num_unknowns = (int)png_get_unknown_chunks(read_ptr,
+                      read_info_ptr, &unknowns);
+
+#ifndef PNG_HAVE_IHDR
+#define PNG_HAVE_IHDR 0x01
+#endif
+                    if (ster_mode >= 0)
+                      png_set_unknown_chunk_location(read_ptr, read_info_ptr,
+                         num_unknowns - 1, (int)PNG_HAVE_IHDR);
+
+                    P1("Found %d unknown chunks\n", num_unknowns);
+
+                    if (nosave == 0 && num_unknowns) {
+                        png_unknown_chunkp unknowns_keep; /* allocated by us */
+                        int num_unknowns_keep;
+
+                        unknowns_keep = (png_unknown_chunk*)png_malloc(
+                          write_ptr, (png_uint_32) num_unknowns
+                          *sizeof(png_unknown_chunk));
+
+                        P1("malloc for %d unknown chunks\n", num_unknowns);
+                        num_unknowns_keep = 0;
+
+                        /* make an array of only those chunks we want to keep */
+                        for (i = 0; i < num_unknowns; i++) {
+                            P1("Handling unknown chunk %d %s\n", i,
+                               (char *)unknowns[i].name);
+                            /* not EBCDIC-safe, but neither is keep_chunks(): */
+                            P2("   unknown[%d] = %s (%lu bytes, location %d)\n",
+                              i, unknowns[i].name,
+                              (unsigned long)unknowns[i].size,
+                              unknowns[i].location);
+                            if (keep_chunk((char *)unknowns[i].name, argv)) {
+                                png_memcpy(&unknowns_keep[num_unknowns_keep],
+                                  &unknowns[i], sizeof(png_unknown_chunk));
+                                ++num_unknowns_keep;
+                            }
+                        }
+
+                        P1("Keeping %d unknown chunks\n", num_unknowns_keep);
+                        png_set_unknown_chunks(write_ptr, write_info_ptr,
+                          unknowns_keep, num_unknowns_keep);
+
+                        /* relevant location bits:
+                         *   (1) !PNG_HAVE_PLTE && !PNG_HAVE_IDAT (before PLTE)
+                         *   (2)  PNG_HAVE_PLTE && !PNG_HAVE_IDAT (between)
+                         *   (3)  PNG_AFTER_IDAT                  (after IDAT)
+                         * PNG_HAVE_PLTE  = 0x02
+                         * PNG_HAVE_IDAT  = 0x04
+                         * PNG_AFTER_IDAT = 0x08
+                         */
+                        for (i = 0; i < num_unknowns_keep; i++) {
+                            png_set_unknown_chunk_location(write_ptr,
+                              write_info_ptr, i,
+                              (int)unknowns_keep[i].location);
+                        }
+
+                        /* png_set_unknown_chunks() makes own copy, so nuke
+                         * ours */
+                        png_free(write_ptr, unknowns_keep);
+                    }
+                }
+              P0("unknown chunk handling done.\n");
+#endif /* PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */
+
+                /* } GRR added for quick %-navigation (1) */
+
+                png_read_transform_info(read_ptr, read_info_ptr);
+
+
+                /* this is the default case (nosave == 1 -> perf-testing
+                   only) */
+                if (nosave == 0) {
+
+                    if (filter_type == 0)
+                        png_set_filter(write_ptr, 0, PNG_FILTER_NONE);
+                    else if (filter_type == 1)
+                        png_set_filter(write_ptr, 0, PNG_FILTER_SUB);
+                    else if (filter_type == 2)
+                        png_set_filter(write_ptr, 0, PNG_FILTER_UP);
+                    else if (filter_type == 3)
+                        png_set_filter(write_ptr, 0, PNG_FILTER_AVG);
+                    else if (filter_type == 4)
+                        png_set_filter(write_ptr, 0, PNG_FILTER_PAETH);
+                    else if (filter_type == 5)
+                        png_set_filter(write_ptr, 0, PNG_ALL_FILTERS);
+                    else
+                        png_set_filter(write_ptr, 0, PNG_FILTER_NONE);
+
+
+/* GRR 20050220: not clear why unknowns treated differently from other chunks */
+/*               (i.e., inside nosave==0 block)...  Moved up 50 lines now. */
+#if 0 /* #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */
+                    {
+                        png_unknown_chunkp unknowns;
+                        int num_unknowns = (int) png_get_unknown_chunks(
+                          read_ptr, read_info_ptr, &unknowns);
+
+                        P1("Keeping %d unknown chunks\n", num_unknowns);
+                        if (num_unknowns) {
+                            png_set_unknown_chunks(write_ptr, write_info_ptr,
+                              unknowns, num_unknowns);
+                            for (i = 0; i < num_unknowns; i++) {
+                                P2("  unknown[%d] = %s\n", i, unknowns[i].name);
+                                png_set_unknown_chunk_location(write_ptr,
+                                  write_info_ptr, i, (int)unknowns[i].location);
+                            }
+                        }
+                    }
+#endif /* 0, was PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */
+
+#ifdef PNGCRUSH_LOCO
+                    if (do_loco) {
+                        png_byte buff[30];
+                        const png_byte png_MHDR[5] = { 77, 72, 68, 82, '\0' };
+                        png_byte mng_signature[8] =
+                            { 138, 77, 78, 71, 13, 10, 26, 10 };
+                        /* write the MNG 8-byte signature */
+                        if (outname[strlen(outname) - 3] == 'p')
+                            png_warning(read_ptr,
+                              "  Writing a MNG file with a .png extension");
+                        png_default_write_data(write_ptr, &mng_signature[0],
+                                       (png_size_t) 8);
+                        png_set_sig_bytes(write_ptr, 8);
+
+                        /* Write a MHDR chunk */
+
+                        buff[0] = (png_byte) ((width >> 24) & 0xff);
+                        buff[1] = (png_byte) ((width >> 16) & 0xff);
+                        buff[2] = (png_byte) ((width >> 8) & 0xff);
+                        buff[3] = (png_byte) ((width) & 0xff);
+                        buff[4] = (png_byte) ((height >> 24) & 0xff);
+                        buff[5] = (png_byte) ((height >> 16) & 0xff);
+                        buff[6] = (png_byte) ((height >> 8) & 0xff);
+                        buff[7] = (png_byte) ((height) & 0xff);
+                        for (i = 8; i < 27; i++)
+                            buff[i] = 0x00;
+                        buff[15] = 2; /* layer count */
+                        buff[19] = 1; /* frame count */
+                        if (output_color_type == 6)
+                            buff[27] = 0x09; /* profile: MNG-VLC with trans. */
+                        else
+                            buff[27] = 0x01;  /* profile: MNG-VLC */
+                        png_write_chunk(write_ptr, (png_bytep) png_MHDR,
+                                        buff, (png_size_t) 28);
+                    }
+#endif /* PNGCRUSH_LOCO */
+
+                    png_crush_pause();
+
+                    if (found_CgBI)
+                        png_warning(read_ptr,
+                            "Cannot read Xcode CgBI PNG. Even if we could,");
+                        png_error(read_ptr,
+                            "the original PNG could not be recovered.");
+
+                    P1( "\nWriting info struct\n");
+
+#if 0 /* doesn't work; compression level has to be the same as in IDAT */
+                    /* if zTXt other compressed chunk */
+                    png_set_compression_level(write_ptr, 9);
+                    png_set_compression_window_bits(write_ptr, 15);
+#endif
+
+                    png_crush_pause();
+                      {
+                        int compression_window;
+                        png_uint_32 zbuf_size;
+                        png_uint_32 required_window;
+                        int channels = 0;
+                        png_set_compression_strategy(write_ptr,
+                                                     z_strategy);
+                        png_set_compression_mem_level(write_ptr,
+                                                      compression_mem_level);
+
+                        if (output_color_type == 0)
+                            channels = 1;
+                        if (output_color_type == 2)
+                            channels = 3;
+                        if (output_color_type == 3)
+                            channels = 1;
+                        if (output_color_type == 4)
+                            channels = 2;
+                        if (output_color_type == 6)
+                            channels = 4;
+
+                        required_window =
+                            (png_uint_32) (height *
+                                           ((width * channels * bit_depth +
+                                             15) >> 3) + 262);
+
+                        zbuf_size =
+                            png_get_compression_buffer_size(write_ptr);
+
+                        /* reinitialize zbuf - compression buffer */
+                        if (zbuf_size != max_idat_size) {
+                            png_uint_32 max_possible_size =
+                                required_window;
+                            if (max_possible_size > max_idat_size)
+                                max_possible_size = max_idat_size;
+                            P2("reinitializing write zbuf to %lu.\n",
+                               (unsigned long)max_possible_size);
+                            png_set_compression_buffer_size(write_ptr,
+                                                            max_possible_size);
+                        }
+
+#ifdef WBITS_8_OK
+                        if (required_window <= 256)
+                            compression_window = 8;
+                        else if (required_window <= 512)
+                            compression_window = 9;
+#else
+                        if (required_window <= 512)
+                            compression_window = 9;
+#endif
+                        else if (required_window <= 1024)
+                            compression_window = 10;
+                        else if (required_window <= 2048)
+                            compression_window = 11;
+                        else if (required_window <= 4096)
+                            compression_window = 12;
+                        else if (required_window <= 8192)
+                            compression_window = 13;
+                        else if (required_window <= 16384)
+                            compression_window = 14;
+                        else
+                            compression_window = 15;
+                        if (compression_window > default_compression_window
+                            || force_compression_window)
+                            compression_window =
+                                default_compression_window;
+
+                        if (verbose > 1 && first_trial
+                            && (compression_window != 15
+                                || force_compression_window))
+                            fprintf(STDERR,
+                                    "   Compression window for output= %d\n",
+                                    1 << compression_window);
+
+                        png_set_compression_window_bits(write_ptr,
+                                                        compression_window);
+                      }
+
+                    png_set_compression_level(write_ptr, zlib_level);
+                    png_write_info(write_ptr, write_info_ptr);
+                    P1( "\nWrote info struct\n");
+#ifdef PNG_WRITE_PACK_SUPPORTED
+                    if (output_bit_depth < 8) {
+                        if (output_color_type == 0) {
+                            png_color_8 true_bits;
+                            true_bits.gray = (png_byte) (output_bit_depth);
+                            png_set_shift(write_ptr, &true_bits);
+                        }
+                        png_set_packing(write_ptr);
+                    }
+#endif
+                } /* no save */
+#define LARGE_PNGCRUSH
+
+#ifdef PNGCRUSH_MULTIPLE_ROWS
+                rows_at_a_time = max_rows_at_a_time;
+                if (rows_at_a_time == 0 || rows_at_a_time < height)
+                    rows_at_a_time = height;
+#endif
+
+#ifndef LARGE_PNGCRUSH
+                {
+                    png_uint_32 rowbytes_s;
+                    png_uint_32 rowbytes;
+
+                    rowbytes = png_get_rowbytes(read_ptr, read_info_ptr);
+
+                    rowbytes_s = (png_size_t) rowbytes;
+                    if (rowbytes == (png_uint_32) rowbytes_s)
+#ifdef PNGCRUSH_MULTIPLE_ROWS
+                        row_buf =
+                            png_malloc(read_ptr,
+                                       rows_at_a_time * rowbytes + 16);
+#else
+                        row_buf = png_malloc(read_ptr, rowbytes + 16);
+#endif
+                    else
+                        row_buf = NULL;
+                }
+#else
+                {
+                    png_uint_32 read_row_length, write_row_length;
+                    read_row_length =
+                        (png_uint_32) (png_get_rowbytes
+                                       (read_ptr, read_info_ptr));
+                    write_row_length =
+                        (png_uint_32) (png_get_rowbytes
+                                       (write_ptr, write_info_ptr));
+                    row_length =
+                        read_row_length >
+                        write_row_length ? read_row_length :
+                        write_row_length;
+#ifdef PNGCRUSH_MULTIPLE_ROWS
+                    row_buf =
+                        (png_bytep) png_malloc(read_ptr,
+                                               rows_at_a_time *
+                                               row_length + 16);
+#else
+                    row_buf =
+                        (png_bytep) png_malloc(read_ptr, row_length + 16);
+#endif
+                }
+#endif
+
+                if (row_buf == NULL)
+                    png_error(read_ptr,
+                              "Insufficient memory to allocate row buffer");
+
+                {
+                    /* check for sufficient memory: we need 2*zlib_window and,
+                       if filter_type == 5, 4*rowbytes in separate allocations.
+                       If it's not enough we can drop the "average" filter and
+                       we can reduce the zlib_window for writing.  We can't
+                       change the input zlib_window because the input file
+                       might have used the full 32K sliding window.
+                     */
+                }
+
+#ifdef PNGCRUSH_MULTIPLE_ROWS
+                row_pointers = (png_bytepp) png_malloc(read_ptr,
+                                                       rows_at_a_time *
+                                                       sizeof(png_bytepp));
+                for (i = 0; i < rows_at_a_time; i++)
+                    row_pointers[i] = row_buf + i * row_length;
+#endif
+
+                P2("allocated rowbuf.\n");
+                png_crush_pause();
+
+                num_pass = png_set_interlace_handling(read_ptr);
+                if (nosave == 0)
+                    png_set_interlace_handling(write_ptr);
+
+                t_stop = (TIME_T) clock();
+                t_misc += (t_stop - t_start);
+                if (t_stop < t_start) {
+                    t_misc += PNG_UINT_31_MAX;
+                    if (t_stop < 0)
+                        t_misc += PNG_UINT_31_MAX;
+                }
+                t_start = t_stop;
+                for (pass = 0; pass < num_pass; pass++) {
+#ifdef PNGCRUSH_MULTIPLE_ROWS
+                    png_uint_32 num_rows;
+#endif
+                    P1( "\nBegin interlace pass %d\n", pass);
+#ifdef PNGCRUSH_MULTIPLE_ROWS
+                    num_rows = rows_at_a_time;
+                    for (y = 0; y < height; y += rows_at_a_time)
+#else
+                    for (y = 0; y < height; y++)
+#endif
+                    {
+#ifdef PNGCRUSH_MULTIPLE_ROWS
+                        if (y + num_rows > height)
+                            num_rows = height - y;
+                        png_read_rows(read_ptr, row_pointers,
+                                      (png_bytepp) NULL, num_rows);
+#else
+                        png_read_row(read_ptr, row_buf, (png_bytep) NULL);
+#endif
+                        if (nosave == 0) {
+                            t_stop = (TIME_T) clock();
+                            t_decode += (t_stop - t_start);
+                            if (t_stop < t_start) {
+                                t_decode += PNG_UINT_31_MAX;
+                                if (t_stop < 0)
+                                    t_decode += PNG_UINT_31_MAX;
+                            }
+                            t_start = t_stop;
+#ifdef PNGCRUSH_MULTIPLE_ROWS
+                            png_write_rows(write_ptr, row_pointers,
+                                           num_rows);
+#else
+                            png_write_row(write_ptr, row_buf);
+#endif
+                            t_stop = (TIME_T) clock();
+                            t_encode += (t_stop - t_start);
+                            if (t_stop < t_start) {
+                                t_encode += PNG_UINT_31_MAX;
+                                if (t_stop < 0)
+                                    t_encode += PNG_UINT_31_MAX;
+                            }
+                            t_start = t_stop;
+                        }
+                    }
+                    P2( "End interlace pass %d\n\n", pass);
+                }
+                if (nosave) {
+                    t_stop = (TIME_T) clock();
+                    t_decode += (t_stop - t_start);
+                    if (t_stop < t_start) {
+                        t_decode += PNG_UINT_31_MAX;
+                        if (t_stop < 0)
+                            t_decode += PNG_UINT_31_MAX;
+                    }
+                    t_start = t_stop;
+                }
+
+#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) && \
+    defined(PNG_FLOATING_POINT_SUPPORTED)
+                if ((color_type == 2 || color_type == 6 || color_type == 3)
+                    && (output_color_type == 0 || output_color_type == 4))
+                {
+                    png_byte rgb_error =
+                        png_get_rgb_to_gray_status(read_ptr);
+                    if ((first_trial) && rgb_error)
+                        printf(
+                          "   **** Converted non-gray image to gray. **** \n");
+                }
+#endif
+
+#ifdef PNG_FREE_UNKN
+#  if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+                png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1);
+#  endif
+#  if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
+                png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1);
+#  endif
+#else
+#  if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED)
+                png_free_unknown_chunks(read_ptr, read_info_ptr, -1);
+#  endif
+#  if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
+                png_free_unknown_chunks(write_ptr, write_info_ptr, -1);
+#  endif
+#endif
+                P1( "Reading and writing end_info data\n");
+                png_read_end(read_ptr, end_info_ptr);
+
+                /* { GRR:  added for %-navigation (2) */
+
+#if (defined(PNG_READ_tEXt_SUPPORTED) && defined(PNG_WRITE_tEXt_SUPPORTED)) \
+ || (defined(PNG_READ_zTXt_SUPPORTED) && defined(PNG_WRITE_zTXt_SUPPORTED))
+                {
+                    png_textp text_ptr;
+                    int num_text = 0;
+
+                    if (png_get_text
+                        (read_ptr, end_info_ptr, &text_ptr, &num_text) > 0
+                        || text_inputs) {
+                        int ntext;
+                        P1( "Handling %d tEXt/zTXt chunks\n",
+                                   num_text);
+
+                        if (verbose > 1 && first_trial && num_text > 0) {
+                            for (ntext = 0; ntext < num_text; ntext++) {
+                                fprintf(STDERR, "%d  %s", ntext,
+                                        text_ptr[ntext].key);
+                                if (text_ptr[ntext].text_length)
+                                    fprintf(STDERR, ": %s\n",
+                                            text_ptr[ntext].text);
+#ifdef PNG_iTXt_SUPPORTED
+                                else if (text_ptr[ntext].itxt_length) {
+                                    fprintf(STDERR, " (%s: %s): \n",
+                                            text_ptr[ntext].lang,
+                                            text_ptr[ntext].lang_key);
+                                    fprintf(STDERR, "%s\n",
+                                            text_ptr[ntext].text);
+                                }
+#endif
+                                else
+                                    fprintf(STDERR, "\n");
+                            }
+                        }
+                        if (nosave) {
+                          if (num_text > 0) {
+                            if (keep_chunk("text", argv)) {
+                                int num_to_write = num_text;
+                                for (ntext = 0; ntext < num_text; ntext++) {
+                                    if (first_trial)
+                                        P2("Text chunk after IDAT, "
+                                          "compression=%d\n",
+                                          text_ptr[ntext].compression);
+                                    if (text_ptr[ntext].compression ==
+                                        PNG_TEXT_COMPRESSION_NONE) {
+                                        if (!keep_chunk("tEXt", argv)) {
+                                            text_ptr[ntext].key[0] = '\0';
+                                            num_to_write--;
+                                        }
+                                    }
+                                    if (text_ptr[ntext].compression ==
+                                        PNG_TEXT_COMPRESSION_zTXt) {
+                                        if (!keep_chunk("zTXt", argv)) {
+                                            text_ptr[ntext].key[0] = '\0';
+                                            num_to_write--;
+                                        }
+                                    }
+#ifdef PNG_iTXt_SUPPORTED
+                                    if (text_ptr[ntext].compression ==
+                                        PNG_ITXT_COMPRESSION_NONE
+                                        || text_ptr[ntext].compression ==
+                                        PNG_ITXT_COMPRESSION_zTXt) {
+                                        if (!keep_chunk("iTXt", argv)) {
+                                            text_ptr[ntext].key[0] = '\0';
+                                            num_to_write--;
+                                        }
+                                    }
+#endif
+                                }
+                                if (num_to_write > 0)
+                                    png_set_text(write_ptr,
+                                                 write_end_info_ptr,
+                                                 text_ptr, num_text);
+                            }
+                        }
+                        for (ntext = 0; ntext < text_inputs; ntext++) {
+                            if (text_where[ntext] == 2) {
+                                png_textp added_text;
+                                added_text = (png_textp)
+                                    png_malloc(write_ptr,
+                                               (png_uint_32)
+                                               sizeof(png_text));
+                                added_text[0].key =
+                                    &text_keyword[ntext * 80];
+#ifdef PNG_iTXt_SUPPORTED
+                                added_text[0].lang =
+                                    &text_lang[ntext * 80];
+                                added_text[0].lang_key =
+                                    &text_lang_key[ntext * 80];
+#endif
+                                added_text[0].text =
+                                    &text_text[ntext * 2048];
+                                added_text[0].compression =
+                                    text_compression[ntext];
+                                png_set_text(write_ptr, write_end_info_ptr,
+                                             added_text, 1);
+                                if (added_text[0].compression < 0)
+                                    printf("   Added a tEXt chunk.\n");
+                                else if (added_text[0].compression == 0)
+                                    printf("   Added a zTXt chunk.\n");
+#ifdef PNG_iTXt_SUPPORTED
+                                else if (added_text[0].compression == 1)
+                                    printf("   Added an uncompressed iTXt "
+                                      "chunk.\n");
+                                else
+                                    printf("   Added a compressed iTXt "
+                                      "chunk.\n");
+#endif
+                                png_free(write_ptr, added_text);
+                                added_text = (png_textp) NULL;
+                            }
+                        }
+                      } /* end of nosave block */
+                    }
+                }
+#endif /* (PNG_READ_tEXt_SUPPORTED and PNG_WRITE_tEXt_SUPPORTED) or */
+       /* (PNG_READ_zTXt_SUPPORTED and PNG_WRITE_zTXt_SUPPORTED) */
+#if defined(PNG_READ_tIME_SUPPORTED) && defined(PNG_WRITE_tIME_SUPPORTED)
+                {
+                    png_timep mod_time;
+
+                    if (png_get_tIME(read_ptr, end_info_ptr, &mod_time)) {
+                        if (keep_chunk("tIME", argv))
+                            png_set_tIME(write_ptr, write_end_info_ptr,
+                                         mod_time);
+                    }
+                }
+#endif
+
+#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED)
+                /* GRR FIXME?  this block may need same fix as above */
+                {
+                    png_unknown_chunkp unknowns;
+                    int num_unknowns =
+                        (int) png_get_unknown_chunks(read_ptr,
+                                                     end_info_ptr,
+                                                     &unknowns);
+                    if (num_unknowns && nosave == 0) {
+                        printf("setting %d unknown chunks after IDAT\n",
+                               num_unknowns);
+                        png_set_unknown_chunks(write_ptr,
+                                               write_end_info_ptr,
+                                               unknowns, num_unknowns);
+                        for (i = 0; i < num_unknowns; i++)
+                            png_set_unknown_chunk_location(write_ptr,
+                                                           write_end_info_ptr,
+                                                           i,
+                                                           (int)
+                                                           unknowns[i].
+                                                           location);
+                    }
+                }
+#endif
+                /* } GRR:  added for %-navigation (2) */
+
+                if (nosave == 0) {
+#if 0 /* doesn't work; compression level has to be the same as in IDAT */
+                    /* if zTXt other compressed chunk */
+                    png_set_compression_level(write_ptr, 9);
+                    png_set_compression_window_bits(write_ptr, 15);
+                    png_set_compression_buffer_size(write_ptr,
+                                                    PNG_ZBUF_SIZE);
+                    png_set_compression_strategy(write_ptr, 0);
+#endif
+                    png_write_end(write_ptr, write_end_info_ptr);
+                }
+
+                P1( "Destroying data structs\n");
+                if (row_buf != (png_bytep) NULL) {
+                    png_free(read_ptr, row_buf);
+                    row_buf = (png_bytep) NULL;
+                }
+#ifdef PNGCRUSH_MULTIPLE_ROWS
+                if (row_pointers != (png_bytepp) NULL) {
+                    png_free(read_ptr, row_pointers);
+                    row_pointers = (png_bytepp) NULL;
+                }
+#endif
+                png_destroy_read_struct(&read_ptr, &read_info_ptr,
+                                        &end_info_ptr);
+                if (nosave == 0) {
+#ifdef PNGCRUSH_LOCO
+                    if (do_loco) {
+                        const png_byte png_MEND[5] =
+                            { 77, 69, 78, 68, '\0' };
+                        /* write the MNG MEND chunk */
+                        png_write_chunk(write_ptr, (png_bytep) png_MEND,
+                                        NULL, (png_size_t) 0);
+                    }
+#endif
+                    png_destroy_info_struct(write_ptr,
+                                            &write_end_info_ptr);
+                    png_destroy_write_struct(&write_ptr, &write_info_ptr);
+                }
+            }
+            Catch(msg) {
+                if (nosave == 0)
+                    fprintf(stderr, "While converting %s to %s:\n", inname,
+                      outname);
+                else
+                    fprintf(stderr, "While reading %s:\n", inname);
+                fprintf(stderr,
+                  "  pngcrush caught libpng error:\n   %s\n\n", msg);
+                if (row_buf) {
+                    png_free(read_ptr, row_buf);
+                    row_buf = (png_bytep) NULL;
+                }
+#ifdef PNGCRUSH_MULTIPLE_ROWS
+                if (row_pointers != (png_bytepp) NULL) {
+                    png_free(read_ptr, row_pointers);
+                    row_pointers = (png_bytepp) NULL;
+                }
+#endif
+                if (nosave == 0) {
+                    png_destroy_info_struct(write_ptr,
+                                            &write_end_info_ptr);
+                    png_destroy_write_struct(&write_ptr, &write_info_ptr);
+                    FCLOSE(fpout);
+                    setfiletype(outname);
+                }
+                png_destroy_read_struct(&read_ptr, &read_info_ptr,
+                                        &end_info_ptr);
+                FCLOSE(fpin);
+                if (verbose > 1)
+                    fprintf(stderr, "returning after cleanup\n");
+                trial = MAX_METHODS + 1;
+            }
+
+            read_ptr = NULL;
+            write_ptr = NULL;
+            FCLOSE(fpin);
+            if (nosave == 0) {
+                FCLOSE(fpout);
+                setfiletype(outname);
+            }
+
+            if (nosave)
+                break;
+
+            first_trial = 0;
+
+            if (nosave == 0) {
+                P1( "Opening file for length measurement\n");
+                if ((fpin = FOPEN(outname, "rb")) == NULL) {
+                    fprintf(STDERR, "Could not find output file %s\n", outname);
+                    if (png_row_filters != NULL) {
+                        free(png_row_filters);
+                        png_row_filters = NULL;
+                    }
+                    exit(1);
+                }
+                number_of_open_files++;
+
+                idat_length[trial] = measure_idats(fpin);
+
+                FCLOSE(fpin);
+            }
+
+            if (verbose > 0 && trial != MAX_METHODS) {
+                fprintf(STDERR,
+                  "   IDAT length with method %3d (fm %d zl %d zs %d) = %8lu\n",
+                  trial, filter_type, zlib_level, z_strategy,
+                  (unsigned long)idat_length[trial]);
+                fflush(STDERR);
+            }
+
+        } /* end of trial-loop */
+       
+        P1("\n\nFINISHED MAIN LOOP OVER %d METHODS\n\n\n", MAX_METHODS);
+
+        /* ////////////////////////////////////////////////////////////////////
+        //////////////////                                 ////////////////////
+        //////////////////  END OF MAIN LOOP OVER METHODS  ////////////////////
+        //////////////////                                 ////////////////////
+        //////////////////////////////////////////////////////////////////// */
+        }
+
+        if (fpin) {
+            FCLOSE(fpin);
+        }
+        if (nosave == 0 && fpout) {
+            FCLOSE(fpout);
+            setfiletype(outname);
+        }
+
+        if (nosave == 0) {
+            png_uint_32 input_length, output_length;
+#ifndef __riscos
+            struct stat stat_buf;
+            struct utimbuf utim;
+
+            stat(inname, &stat_buf);
+            input_length = (unsigned long) stat_buf.st_size;
+            utim.actime  = stat_buf.st_atime;
+            utim.modtime = stat_buf.st_mtime;
+            stat(outname, &stat_buf);
+            output_length = (unsigned long) stat_buf.st_size;
+            if (new_time_stamp == 0) {
+              /* set file timestamp (no big deal if fails) */
+              utime(outname, &utim);
+            }
+#else
+            input_length = (unsigned long) filesize(inname);
+            output_length = (unsigned long) filesize(outname);
+#endif
+        if (verbose > 0) {
+            total_input_length += input_length + output_length;
+
+            if (!already_crushed && !image_is_immutable) {
+            fprintf(STDERR, "   Best pngcrush method = %d (fm %d zl %d zs %d) "
+              "for %s\n", best, fm[best], lv[best], zs[best], outname);
+            }
+            if (idat_length[0] == idat_length[best])
+                fprintf(STDERR, "     (no IDAT change)\n");
+            else if (idat_length[0] > idat_length[best])
+                fprintf(STDERR, "     (%4.2f%% IDAT reduction)\n",
+                  (100.0 - (100.0 * idat_length[best]) / idat_length[0]));
+            else
+                fprintf(STDERR, "     (%4.2f%% IDAT increase)\n",
+                  -(100.0 - (100.0 * idat_length[best]) / idat_length[0]));
+            if (input_length == output_length)
+                fprintf(STDERR, "     (no filesize change)\n\n");
+            else if (input_length > output_length)
+                fprintf(STDERR, "     (%4.2f%% filesize reduction)\n\n",
+                  (100.0 - (100.0 * output_length) / input_length));
+            else
+                fprintf(STDERR, "     (%4.2f%% filesize increase)\n\n",
+                  -(100.0 - (100.0 * output_length) / input_length));
+
+            if (verbose > 2)
+                fprintf(STDERR, "   Number of open files=%d\n",
+                  number_of_open_files);
+
+          }
+        }
+
+        if (pngcrush_mode == DEFAULT_MODE) {
+            if (png_row_filters != NULL) {
+                free(png_row_filters);
+                png_row_filters = NULL;
+            }
+            if (verbose > 0)
+                show_result();
+#ifdef PNG_iCCP_SUPPORTED
+            if (iccp_length)
+                free(iccp_text);
+#endif
+            if (pngcrush_must_exit)
+                exit(0);
+            return 0;
+        }
+    } /* end of loop on input files */
+
+    return 0;  /* just in case */
+
+} /* end of main() */
+
+
+
+
+png_uint_32 measure_idats(FILE * fp_in)
+{
+    /* Copyright (C) 1999-2002,2006 Glenn Randers-Pehrson (glennrp@users.sf.net)
+       See notice in pngcrush.c for conditions of use and distribution */
+    P2("\nmeasure_idats:\n");
+    P1( "Allocating read structure\n");
+/* OK to ignore any warning about the address of exception__prev in "Try" */
+    Try {
+        read_ptr =
+            png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL,
+                                   (png_error_ptr) png_cexcept_error,
+                                   (png_error_ptr) NULL);
+        P1( "Allocating read_info,  end_info structures\n");
+        read_info_ptr = png_create_info_struct(read_ptr);
+        end_info_ptr = png_create_info_struct(read_ptr);
+
+#if !defined(PNG_NO_STDIO)
+        png_init_io(read_ptr, fp_in);
+#else
+        png_set_read_fn(read_ptr, (png_voidp) fp_in, (png_rw_ptr) NULL);
+#endif
+
+        png_set_sig_bytes(read_ptr, 0);
+        measured_idat_length = png_measure_idat(read_ptr);
+        P2("measure_idats: IDAT length=%lu\n",
+          (unsigned long)measured_idat_length);
+        P1( "Destroying data structs\n");
+        png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
+    }
+    Catch(msg) {
+        fprintf(STDERR, "\nWhile measuring IDATs in %s ", inname);
+        fprintf(STDERR, "pngcrush caught libpng error:\n   %s\n\n", msg);
+        png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr);
+        P1( "Destroyed data structs\n");
+        measured_idat_length = 0;
+    }
+    return measured_idat_length;
+}
+
+
+
+
+
+png_uint_32 png_measure_idat(png_structp png_ptr)
+{
+    /* Copyright (C) 1999-2002,2006 Glenn Randers-Pehrson (glennrp@users.sf.net)
+       See notice in pngcrush.c for conditions of use and distribution */
+    png_uint_32 sum_idat_length = 0;
+    png_byte *bb = NULL;
+    png_uint_32 malloced_length=0;
+
+    {
+        png_byte png_signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
+#if defined(PNGCRUSH_LOCO)
+        png_byte mng_signature[8] = { 138, 77, 78, 71, 13, 10, 26, 10 };
+#endif
+
+        png_default_read_data(png_ptr, png_signature, 8);
+        png_set_sig_bytes(png_ptr, 8);
+
+#if defined(PNGCRUSH_LOCO)
+        if (!(int) (png_memcmp(mng_signature, png_signature, 8))) {
+            const png_byte png_MHDR[5] = { 77, 72, 68, 82, '\0' };
+
+            int b;
+            png_byte buff[40];
+            unsigned long length;
+            /* read the MHDR */
+            png_default_read_data(read_ptr, buff, 4);
+            length=buff[3]+(buff[2]<<8)+(buff[1]<<16)+(buff[0]<<24);
+            png_default_read_data(read_ptr, buff, 4);
+            printf("Reading %c%c%c%c chunk.\n",buff[0],buff[1],
+              buff[2],buff[3]);
+            for (b=0; b<40; b++)
+              buff[b]='\0';
+            png_default_read_data(read_ptr, buff, length);
+            if (verbose) {
+            printf("  width=%lu\n",(unsigned long)(buff[3]+(buff[2]<<8)
+                      +(buff[1]<<16)+(buff[0]<<24)));
+            printf("  height=%lu\n",(unsigned long)(buff[7]+(buff[6]<<8)
+                      +(buff[5]<<16)+(buff[4]<<24)));
+            printf("  ticksps=%lu\n",(unsigned long)(buff[11]+
+                     (buff[10]<<8)+(buff[9]<<16)+(buff[8]<<24)));
+            printf("  nomlayc=%lu\n",(unsigned long)(buff[15]+
+                     (buff[14]<<8)+(buff[13]<<16)+(buff[12]<<24)));
+            printf("  nomfram=%lu\n",(unsigned long)(buff[19]+
+                     (buff[18]<<8)+(buff[17]<<16)+(buff[16]<<24)));
+            printf("  nomplay=%lu\n",(unsigned long)(buff[23]+
+                     (buff[22]<<8)+(buff[21]<<16)+(buff[20]<<24)));
+            printf("  profile=%lu\n",(unsigned long)(buff[27]+
+                     (buff[26]<<8)+(buff[25]<<16)+(buff[24]<<24)));
+            }
+
+            if (new_mng) {
+            /* write the MNG 8-byte signature */
+            png_default_write_data(mng_ptr, &mng_signature[0],
+                                  (png_size_t) 8);
+
+                        /* Write a MHDR chunk */
+            png_write_chunk(mng_ptr, (png_bytep) png_MHDR,
+                            buff, (png_size_t) 28);
+            }
+
+            png_default_read_data(read_ptr, buff, 4);
+            input_format = 1;
+
+        } else
+#endif
+        if (png_sig_cmp(png_signature, 0, 8)) {
+            if (png_sig_cmp(png_signature, 0, 4))
+                png_error(png_ptr, "Not a PNG file..");
+            else
+                png_error(png_ptr,
+                          "PNG file corrupted by ASCII conversion");
+        }
+    }
+
+    if (fix)
+    {
+#ifdef PNG_CRC_WARN_USE
+        png_set_crc_action(png_ptr, PNG_CRC_WARN_USE, PNG_CRC_WARN_USE);
+#endif
+#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
+        inflateUndermine(&png_ptr->zstream, 1);
+#endif
+    }
+
+    for (;;) {
+#ifndef PNG_UINT_IDAT
+#ifdef PNG_USE_LOCAL_ARRAYS
+        PNG_IDAT;
+        PNG_IEND;
+        PNG_IHDR;
+#ifdef PNG_iCCP_SUPPORTED
+        PNG_iCCP;
+#else
+        const png_byte png_iCCP[5] = { 105, 67, 67, 80, '\0' };
+#endif
+#endif
+#endif
+        png_byte chunk_name[5];
+        png_byte chunk_length[4];
+        png_byte buff[32];
+        png_uint_32 length;
+
+        png_default_read_data(png_ptr, chunk_length, 4);
+        length = png_get_uint_31(png_ptr,chunk_length);
+
+        png_reset_crc(png_ptr);
+        png_crc_read(png_ptr, chunk_name, 4);
+
+        if (new_mng) {
+          const png_byte png_DHDR[5] = { 68, 72, 68, 82, '\0' };
+          const png_byte png_DEFI[5] = { 68, 69, 70, 73, '\0' };
+          const png_byte png_FRAM[5] = { 70, 82, 65, 77, '\0' };
+          const png_byte png_nEED[5] = { 110, 69, 69, 68, '\0' };
+          if (!png_memcmp(chunk_name, png_nEED, 4)) {
+          /* Skip the nEED chunk */
+            printf ("  skipping MNG %c%c%c%c chunk, %lu bytes\n",chunk_name[0],
+              chunk_name[1],chunk_name[2],chunk_name[3],(unsigned long)length);
+          }
+          else {
+          /* copy the chunk. */
+            printf ("  reading MNG %c%c%c%c chunk, %lu bytes\n",chunk_name[0],
+              chunk_name[1],chunk_name[2],chunk_name[3],(unsigned long)length);
+            if (length > malloced_length) {
+              png_free(mng_ptr,bb);
+              printf ("  png_malloc %lu bytes.\n",(unsigned long)length);
+              bb=(png_byte*)png_malloc(mng_ptr, length);
+              malloced_length=length;
+            }
+            png_crc_read(png_ptr, bb, length);
+            png_write_chunk(mng_ptr, chunk_name,
+                            bb, (png_size_t) length);
+
+            if (!png_memcmp(chunk_name, png_DHDR, 4)) {
+                if (verbose > 1) {
+                printf("  objid=%lu\n",(unsigned long)(bb[1]+(bb[0]<<8)));
+                printf("  itype=%lu\n",(unsigned long)(bb[2]));
+                printf("  dtype=%lu\n",(unsigned long)(bb[3]));
+                printf("  width=%lu\n",(unsigned long)(bb[7]+(bb[6]<<8)
+                          +(bb[5]<<16)+(bb[4]<<24)));
+                printf("  height=%lu\n",(unsigned long)(bb[11]+(bb[10]<<8)
+                          +(bb[9]<<16)+(bb[8]<<24)));
+                printf("  xloc=%lu\n",(unsigned long)(bb[15]+(bb[14]<<8)
+                          +(bb[13]<<16)+(bb[12]<<24)));
+                printf("  yloc=%lu\n",(unsigned long)(bb[19]+(bb[18]<<8)
+                          +(bb[17]<<16)+(bb[16]<<24)));
+                }
+            }
+
+            if (!png_memcmp(chunk_name, png_DEFI, 4)) {
+                if (verbose > 1) {
+                printf("  objid=%lu\n",(unsigned long)(bb[1]+(bb[0]<<8)));
+                printf("  do_not_show=%lu\n",(unsigned long)(bb[2]));
+                printf("  concrete=%lu\n",(unsigned long)(bb[3]));
+                if (length > 4) {
+                printf("  xloc=%lu\n",(unsigned long)(bb[15]+(bb[14]<<8)
+                          +(bb[13]<<16)+(bb[12]<<24)));
+                printf("  yloc=%lu\n",(unsigned long)(bb[19]+(bb[18]<<8)
+                          +(bb[17]<<16)+(bb[16]<<24)));
+                if (length > 12) {
+                printf("  l_cb=%lu\n",(unsigned long)(bb[20]+(bb[19]<<8)
+                          +(bb[18]<<16)+(bb[17]<<24)));
+                printf("  r_cb=%lu\n",(unsigned long)(bb[24]+(bb[23]<<8)
+                          +(bb[22]<<16)+(bb[21]<<24)));
+                }
+                }
+                }
+            }
+            if (!png_memcmp(chunk_name, png_FRAM, 4)) {
+                if (verbose > 1) {
+                  printf("  mode=%lu\n",(unsigned long)bb[0]);
+                  if (length > 1) {
+                    int ib;
+                    printf("  name = ");
+                    for (ib=0; bb[ib]; ib++)
+                    {
+                      printf ("%c", bb[ib]);
+                    }
+                    printf ("\n");
+                  }
+                }
+            }
+                length=0;
+            }
+        }
+
+        else {
+#ifdef PNG_UINT_IDAT
+        if (png_get_uint_32(chunk_name) == PNG_UINT_IDAT)
+#else
+        if (!png_memcmp(chunk_name, png_IDAT, 4))
+#endif
+        {
+            sum_idat_length += length;
+            if (length > crushed_idat_size)
+                already_crushed++;
+        }
+
+        if (verbose > 1) {
+            chunk_name[4] = '\0';
+            printf("Reading %s chunk, length = %lu.\n", chunk_name,
+                   (unsigned long)length);
+        }
+
+        if (png_get_uint_32(chunk_name) == PNG_UINT_CgBI)
+        {
+          printf(" This is an Xcode CGBI file, not a PNG file.\n");
+          if (fix)
+          {
+            printf (" Removing the CgBI chunk.\n");
+          } else {
+            printf (" Try \"pngcrush -fix ...\" to attempt to read it.\n");
+          }
+          found_CgBI++;
+          nosave++;
+        }
+
+
+#ifdef PNG_UINT_IHDR
+        if (png_get_uint_32(chunk_name) == PNG_UINT_IHDR)
+#else
+        if (!png_memcmp(chunk_name, png_IHDR, 4))
+#endif
+        {
+            /* get the color type */
+            png_crc_read(png_ptr, buff, 13);
+            length -= 13;
+            input_color_type = buff[9];
+        }
+        else {
+          if (png_get_uint_32(chunk_name) == PNG_UINT_dSIG)
+          {
+            if (found_any_chunk == 0 && !all_chunks_are_safe)
+            {
+               image_is_immutable=1;
+            }
+          }
+          else
+            found_any_chunk=1;
+        }
+
+#ifdef PNG_gAMA_SUPPORTED
+        if (png_get_uint_32(chunk_name) == PNG_UINT_gAMA)
+          found_gAMA=1;
+#endif
+
+#ifdef PNG_cHRM_SUPPORTED
+        if (png_get_uint_32(chunk_name) == PNG_UINT_cHRM)
+          found_cHRM=1;
+#endif
+
+#ifdef PNG_iCCP_SUPPORTED
+        /* check for bad Photoshop iCCP chunk */
+#ifdef PNG_UINT_iCCP
+        if (png_get_uint_32(chunk_name) == PNG_UINT_iCCP)
+#else
+        if (!png_memcmp(chunk_name, png_iCCP, 4))
+#endif
+        {
+            /* Check for bad Photoshop iCCP chunk.  Libpng will reject the
+             * bad chunk because the Adler-32 bytes are missing, but we check
+             * here to see if it's really the sRGB profile, and if so, set the
+             * "intent" flag and gamma so pngcrush will write an sRGB chunk
+             * and a gamma chunk.
+             */
+            if (length == 2615) {
+                png_crc_read(png_ptr, buff, 22);
+                length -= 22;
+                buff[23] = 0;
+                if (!strncmp((png_const_charp) buff, "Photoshop ICC profile",
+                     21))
+                {
+                    printf("   Replacing bad Photoshop ICCP chunk with an "
+                      "sRGB chunk\n");
+#ifdef PNG_gAMA_SUPPORTED
+#ifdef PNG_FIXED_POINT_SUPPORTED
+                    image_specified_gamma = 45455L;
+#else
+                    image_specified_gamma = 0.45455;
+#endif
+#endif
+                    intent = 0;
+                }
+            }
+        }
+#endif
+
+    }
+        png_crc_finish(png_ptr, length);
+
+#ifdef PNGCRUSH_LOCO
+#ifdef PNG_UINT_MEND
+        if (png_get_uint_32(chunk_name) == PNG_UINT_MEND)
+            return sum_idat_length;
+#else
+        {
+          const png_byte png_MEND[5] =
+              { 77, 69, 78, 68, '\0' };
+          if (!png_memcmp(chunk_name, png_MEND, 4)) {
+              if (new_mng) {
+                  png_free(mng_ptr,bb);
+                  return (0);
+              }
+              return sum_idat_length;
+          }
+        }
+#endif
+#endif
+
+
+        if (input_format == 0) {
+#ifdef PNG_UINT_IEND
+          if (png_get_uint_32(chunk_name) == PNG_UINT_IEND) {
+#else
+          if (!png_memcmp(chunk_name, png_IEND, 4)) {
+#endif
+            if (!fix && found_CgBI)
+              return 0;
+            else
+              return sum_idat_length;
+          }
+        }
+    }
+}
+
+
+
+
+
+#ifdef PNGCRUSH_COUNT_COLORS
+#define USE_HASHCODE
+int count_colors(FILE * fp_in)
+{
+    /* Copyright (C) 2000-2002,2006 Glenn Randers-Pehrson (glennrp@users.sf.net)
+       See notice in pngcrush.c for conditions of use and distribution */
+    int bit_depth, color_type, interlace_method, filter_method,
+        compression_method;
+    png_uint_32 rowbytes;
+    volatile png_uint_32 channels;
+
+    int i;
+    int pass, num_pass;
+    int ret;
+    volatile int result, hashmiss, hashinserts;
+
+    png_uint_32 rgba_frequency[257];
+
+    png_uint_32 rgba_hi[257];   /* Actually contains ARGB not RGBA */
+#if 0
+    png_uint_32 rgba_lo[257];   /* Low bytes of ARGB in 16-bit PNGs */
+#endif
+
+    /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */
+
+    /* start of interlace block */
+    int png_pass_start[] = { 0, 4, 0, 2, 0, 1, 0 };
+
+    /* offset to next interlace block */
+    int png_pass_inc[] = { 8, 8, 4, 4, 2, 2, 1 };
+
+    /* start of interlace block in the y direction */
+    int png_pass_ystart[] = { 0, 0, 4, 0, 2, 0, 1 };
+
+    /* offset to next interlace block in the y direction */
+    int png_pass_yinc[] = { 8, 8, 8, 4, 4, 2, 2 };
+
+    result = 0;
+    reduce_to_gray = 1;
+    it_is_opaque = 1;
+    hashmiss = 0;
+    hashinserts = 0;
+    row_buf = (png_bytep) NULL;
+
+    num_rgba = 0;
+    for (i = 0; i < 257; i++) {
+        rgba_frequency[i] = 0;
+    }
+
+    P2("Checking alphas:\n");
+    P1( "Allocating read structure\n");
+    Try {
+        read_ptr =
+            png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp) NULL,
+                                   (png_error_ptr) png_cexcept_error,
+                                   (png_error_ptr) NULL);
+        if (read_ptr) {
+            P1( "Allocating read_info structure\n");
+            read_info_ptr = png_create_info_struct(read_ptr);
+            if (read_info_ptr == NULL)
+                png_destroy_read_struct(&read_ptr, (png_infopp) NULL,
+                                        (png_infopp) NULL);
+        } else
+            read_info_ptr = NULL;
+        if (read_info_ptr) {
+
+#ifdef USE_HASHCODE
+            int hash[16385];
+#endif
+
+#ifdef USE_HASHCODE
+            for (i = 0; i < 16385; i++)
+                hash[i] = -1;
+#endif
+            end_info_ptr = NULL;
+
+#if !defined(PNG_NO_STDIO)
+            png_init_io(read_ptr, fp_in);
+#else
+            png_set_read_fn(read_ptr, (png_voidp) fp_in, (png_rw_ptr) NULL);
+#endif
+
+            {
+#if defined(PNGCRUSH_LOCO)
+                png_byte mng_signature[8] =
+                    { 138, 77, 78, 71, 13, 10, 26, 10 };
+#endif
+                png_byte png_signature[8] =
+                    { 137, 80, 78, 71, 13, 10, 26, 10 };
+
+                png_default_read_data(read_ptr, png_signature, 8);
+                png_set_sig_bytes(read_ptr, 8);
+
+#if defined(PNGCRUSH_LOCO)
+                if (!(int) (png_memcmp(mng_signature, png_signature, 8))) {
+                    png_byte buffer[40];
+                    unsigned long length;
+                    /* Skip the MHDR chunk. */
+                    png_skip_chunk(read_ptr);
+                    png_permit_mng_features(read_ptr,
+                                            PNG_FLAG_MNG_FILTER_64);
+                    input_format = 1;
+                } else
+#endif
+                if (png_sig_cmp(png_signature, 0, 8)) {
+                    if (png_sig_cmp(png_signature, 0, 4))
+                        png_error(read_ptr, "Not a PNG file.");
+                    else
+                        png_error(read_ptr,
+                           "PNG file corrupted by ASCII conversion");
+                }
+            }
+
+            if (fix && found_CgBI){
+                /* Skip the CgBI chunk. */
+                png_skip_chunk(read_ptr);
+                /* iCCP is probably badly compressed */
+                png_set_keep_unknown_chunks(read_ptr,
+                    PNG_HANDLE_CHUNK_NEVER,
+                    (png_bytep)"iCCP", 1);
+#ifdef PNG_iTXt_SUPPORTED
+                /* and iTXt */
+                png_set_keep_unknown_chunks(read_ptr,
+                    PNG_HANDLE_CHUNK_NEVER,
+                    (png_bytep)"iTXt", 1);
+#endif
+                /* zTXt too */
+                png_set_keep_unknown_chunks(read_ptr,
+                    PNG_HANDLE_CHUNK_NEVER,
+                    (png_bytep)"zTXt", 1);
+            }
+
+            png_read_info(read_ptr, read_info_ptr);
+
+#ifdef PNG_CRC_QUIET_USE
+            png_set_crc_action(read_ptr, PNG_CRC_QUIET_USE,
+                               PNG_CRC_QUIET_USE);
+#endif
+
+            png_get_IHDR(read_ptr, read_info_ptr, &width, &height,
+                         &bit_depth, &color_type, &interlace_method,
+                         &compression_method, &filter_method);
+
+            if (color_type == 2)
+                channels = 3;
+            else if (color_type == 4)
+                channels = 2;
+            else if (color_type == 6)
+                channels = 4;
+            else
+                channels = 1;
+
+            if (color_type == 0 || color_type == 3 || color_type == 4)
+                reduce_to_gray = 1;
+
+            if (bit_depth == 8) {
+                if (interlace_method)
+                    num_pass = 7;
+                else
+                    num_pass = 1;
+
+                rowbytes = png_get_rowbytes(read_ptr, read_info_ptr);
+
+                row_buf = png_malloc(read_ptr, rowbytes + 16);
+
+                for (pass = 0; pass < num_pass; pass++) {
+                    png_byte *rp;
+                    png_uint_32 pass_height, pass_width, y;
+                    P2( "\nBegin count_colors() interlace pass %d\n", pass);
+
+                    if (interlace_method) {
+                        pass_height = (height - png_pass_ystart[pass]
+                                       + png_pass_yinc[pass] -
+                                       1) / png_pass_yinc[pass];
+                        pass_width = (width - png_pass_start[pass]
+                                      + png_pass_inc[pass] -
+                                      1) / png_pass_inc[pass];
+                    } else {
+                        pass_height = height;
+                        pass_width = width;
+                    }
+
+                    for (y = 0; y < pass_height; y++) {
+                        png_uint_32 x;
+                        png_read_row(read_ptr, row_buf, (png_bytep) NULL);
+                        if (result < 2 || it_is_opaque || reduce_to_gray) {
+                            if (color_type == 2) {
+                                for (rp = row_buf, x = 0; x < pass_width;
+                                     x++, rp += channels) {
+#ifdef USE_HASHCODE
+                                    int hashcode;
+#endif
+                                    png_uint_32 rgba_high =
+                                        (255 << 24) | (*(rp) << 16) |
+                                        (*(rp + 1) << 8) | *(rp + 2);
+                                    assert(num_rgba < 258);
+                                    rgba_hi[num_rgba] = rgba_high;
+
+                                    if (reduce_to_gray &&
+                                        ((*(rp)) != (*(rp + 1))
+                                         || (*(rp)) != (*(rp + 2))))
+                                        reduce_to_gray = 0;
+
+                                    if (result > 1 || !it_is_opaque)
+                                        continue;
+
+
+#ifdef USE_HASHCODE
+                                    /*
+                                     *      R      G      B     mask
+                                     *  11,111  0,0000, 0000   0x3e00
+                                     *  00,000  1,1111, 0000   0x01f0
+                                     *  00,000  0,0000, 1111   0x000f
+                                     *
+                                     */
+
+                                    hashcode =
+                                        (int) (((rgba_high >> 10) & 0x3e00)
+                                               | ((rgba_high >> 7) &
+                                                  0x01f0) | ((rgba_high >>
+                                                              4) &
+                                                             0x000f));
+                                    assert(hashcode < 16385);
+                                    if (hash[hashcode] < 0) {
+                                        hash[hashcode] = i = num_rgba;
+                                        if (i > 256)
+                                            result = 2;
+                                        else
+                                            num_rgba++;
+                                    } else {
+                                        int start = hash[hashcode];
+                                        for (i = start; i <= num_rgba; i++)
+                                            if (rgba_high == rgba_hi[i])
+                                                break;
+                                        hashmiss += (i - start);
+                                        if (i == num_rgba) {
+                                            int j;
+                                            if (i > 256)
+                                                result = 2;
+                                            else {
+                                                for (j = num_rgba;
+                                                     j > start + 1; j--) {
+                                                    rgba_hi[j] =
+                                                        rgba_hi[j - 1];
+                                                    rgba_frequency[j] =
+                                                        rgba_frequency[j -
+                                                                       1];
+                                                }
+                                                assert(start + 1 < 258);
+                                                rgba_hi[start + 1] =
+                                                    rgba_high;
+                                                rgba_frequency[start + 1] =
+                                                    0;
+                                                for (j = 0; j < 16384; j++)
+                                                    if (hash[j] > start)
+                                                        hash[j]++;
+                                                i = start + 1;
+                                                hashinserts++;
+                                                num_rgba++;
+                                            }
+                                        }
+                                    }
+#else
+                                    for (i = 0; i <= num_rgba; i++)
+                                        if (rgba_high == rgba_hi[i])
+                                            break;
+                                    hashmiss += i;
+                                    if (i > 256)
+                                        result = 2;
+                                    else if (i == num_rgba)
+                                        num_rgba++;
+#endif
+                                    assert(i < 258);
+                                    ++rgba_frequency[i];
+                                }
+                            } else if (color_type == 6) {
+                                for (rp = row_buf, x = 0; x < pass_width;
+                                     x++, rp += channels) {
+#ifdef USE_HASHCODE
+                                    int hashcode;
+#endif
+                                    png_uint_32 rgba_high =
+                                        (*(rp + 3) << 24) | (*(rp) << 16) |
+                                        (*(rp + 1) << 8) | *(rp + 2);
+                                    assert(rp - row_buf + 3 < rowbytes);
+                                    rgba_hi[num_rgba] = rgba_high;
+                                    if (reduce_to_gray &&
+                                        ((*(rp)) != (*(rp + 1))
+                                         || (*(rp)) != (*(rp + 2))))
+                                        reduce_to_gray = 0;
+                                    if (it_is_opaque && (*(rp + 3)) != 255)
+                                        it_is_opaque = 0;
+                                    if (result > 1)
+                                        continue;
+#ifdef USE_HASHCODE
+                                    /*
+                                     *  A     R     G    B    mask
+                                     * 11,1 000,0 000,0 000   0x3800
+                                     * 00,0 111,1 000,0 000   0x0780
+                                     * 00,0 000,0 111,1 000   0x0078
+                                     * 00,0 000,0 000,0 111   0x0007
+                                     *
+                                     */
+
+                                    hashcode =
+                                        (int) (((rgba_high >> 18) & 0x3800)
+                                               | ((rgba_high >> 12) &
+                                                  0x0780) | ((rgba_high >>
+                                                              8) & 0x0078)
+                                               | ((rgba_high >> 4) &
+                                                  0x0007));
+                                    assert(hashcode < 16385);
+                                    if (hash[hashcode] < 0) {
+                                        hash[hashcode] = i = num_rgba;
+                                        if (i > 256)
+                                            result = 2;
+                                        else
+                                            num_rgba++;
+                                    } else {
+                                        int start = hash[hashcode];
+                                        for (i = start; i <= num_rgba; i++)
+                                            if (rgba_high == rgba_hi[i])
+                                                break;
+                                        hashmiss += (i - start);
+                                        if (i == num_rgba) {
+                                            if (i > 256)
+                                                result = 2;
+                                            else {
+                                                int j;
+                                                for (j = num_rgba;
+                                                     j > start + 1; j--) {
+                                                    rgba_hi[j] =
+                                                        rgba_hi[j - 1];
+                                                    rgba_frequency[j] =
+                                                        rgba_frequency[j -
+                                                                       1];
+                                                }
+                                                rgba_hi[start + 1] =
+                                                    rgba_high;
+                                                rgba_frequency[start + 1] =
+                                                    0;
+                                                for (j = 0; j < 16384; j++)
+                                                    if (hash[j] > start)
+                                                        hash[j]++;
+                                                i = start + 1;
+                                                hashinserts++;
+                                                num_rgba++;
+                                            }
+                                        }
+                                    }
+#else
+                                    for (i = 0; i <= num_rgba; i++)
+                                        if (rgba_high == rgba_hi[i])
+                                            break;
+                                    hashmiss += i;
+                                    if (i > 256)
+                                        result = 2;
+                                    else if (i == num_rgba)
+                                        num_rgba++;
+#endif
+                                    ++rgba_frequency[i];
+                                }
+                            } else if (color_type == 4) {
+                                for (rp = row_buf, x = 0; x < pass_width;
+                                     x++, rp += channels) {
+#ifdef USE_HASHCODE
+                                    int hashcode;
+#endif
+                                    png_uint_32 rgba_high =
+                                        (*(rp + 1) << 24) | (*(rp) << 16) |
+                                        (*(rp) << 8) | (*rp);
+                                    assert(rp - row_buf + 1 < rowbytes);
+                                    rgba_hi[num_rgba] = rgba_high;
+                                    if (it_is_opaque && (*(rp + 1)) != 255)
+                                        it_is_opaque = 0;
+#ifdef USE_HASHCODE
+                                    /*
+                                     *    A          G          mask
+                                     * 11,1111,  0000,0000    0x3f00
+                                     * 00,0000,  1111,1111    0x00ff
+                                     *
+                                     */
+
+                                    hashcode =
+                                        (int) (((rgba_high >> 18) & 0x3f00)
+                                               | ((rgba_high >> 4) &
+                                                  0x00ff));
+                                    if (hash[hashcode] < 0) {
+                                        hash[hashcode] = i = num_rgba;
+                                        if (i > 256)
+                                            result = 2;
+                                        else
+                                            num_rgba++;
+                                    } else {
+                                        int start = hash[hashcode];
+                                        for (i = start; i <= num_rgba; i++)
+                                            if (rgba_high == rgba_hi[i])
+                                                break;
+                                        hashmiss += (i - start);
+                                        if (i == num_rgba) {
+                                            if (i > 256)
+                                                result = 2;
+                                            else {
+                                                int j;
+                                                for (j = num_rgba;
+                                                     j > start + 1; j--) {
+                                                    rgba_hi[j] =
+                                                        rgba_hi[j - 1];
+                                                    rgba_frequency[j] =
+                                                        rgba_frequency[j -
+                                                                       1];
+                                                }
+                                                rgba_hi[start + 1] =
+                                                    rgba_high;
+                                                rgba_frequency[start + 1] =
+                                                    0;
+                                                for (j = 0; j < 16384; j++)
+                                                    if (hash[j] > start)
+                                                        hash[j]++;
+                                                i = start + 1;
+                                                hashinserts++;
+                                                num_rgba++;
+                                            }
+                                        }
+                                    }
+#else
+                                    for (i = 0; i <= num_rgba; i++)
+                                        if (rgba_high == rgba_hi[i])
+                                            break;
+                                    hashmiss += i;
+                                    if (i > 256)
+                                        result = 2;
+                                    else if (i == num_rgba)
+                                        num_rgba++;
+#endif
+                                    ++rgba_frequency[i];
+                                }
+                            } else {    /* other color type */
+
+                                result = 2;
+                            }
+                        }
+                    }
+                    P2( "End count_colors() interlace pass %d\n\n", pass);
+                }
+
+            } else /* (bit_depth != 8) */ {
+
+                /* TO DO: 16-bit support */
+                reduce_to_gray = 0;
+                it_is_opaque = 0;
+                result = 0;
+            }
+
+            png_free(read_ptr, row_buf);
+            row_buf = (png_bytep) NULL;
+            P1( "Destroying data structs\n");
+            png_destroy_read_struct(&read_ptr, &read_info_ptr,
+                                    (png_infopp) NULL);
+        } else
+            result = 2;
+    }
+    Catch(msg) {
+        fprintf(STDERR, "\nWhile checking alphas in %s ", inname);
+        fprintf(STDERR, "pngcrush caught libpng error:\n   %s\n\n", msg);
+        png_free(read_ptr, row_buf);
+        row_buf = (png_bytep) NULL;
+        png_destroy_read_struct(&read_ptr, &read_info_ptr,
+                                (png_infopp) NULL);
+        P1( "Destroyed data structs\n");
+        result = 2;
+    }
+    if (verbose > 1) {
+        int total = 0;
+        if (num_rgba && num_rgba < 257) {
+            for (i = 0; i < num_rgba; i++) {
+                printf("RGBA=(%3.3d,%3.3d,%3.3d,%3.3d), frequency=%d\n",
+                       (int) (rgba_hi[i] >> 16) & 0xff,
+                       (int) (rgba_hi[i] >> 8) & 0xff,
+                       (int) (rgba_hi[i]) & 0xff,
+                       (int) (rgba_hi[i] >> 24) & 0xff,
+                       (int) rgba_frequency[i]);
+                total += rgba_frequency[i];
+            }
+            P2("num_rgba=%d, total pixels=%d\n", num_rgba, total);
+            P2("hashcode misses=%d, inserts=%d\n", hashmiss, hashinserts);
+        }
+        if (color_type == 0 || color_type == 2)
+            it_is_opaque = 0;
+        if (reduction_ok) {
+            if (reduce_to_gray)
+                P1("The truecolor image is all gray and will be reduced.\n");
+            if (it_is_opaque)
+                P1("The image is opaque and the alpha channel will be "
+                  "removed.\n");
+        } else {
+            if (reduce_to_gray)
+                P1("The truecolor image is all gray and could be reduced.\n");
+            if (it_is_opaque)
+                P1("The image is opaque and the alpha channel could be "
+                  "removed.\n");
+            if (reduce_to_gray || it_is_opaque)
+                P1("Rerun pngcrush with the \"-reduce\" option to do so.\n");
+            reduce_to_gray = 0;
+            it_is_opaque = 0;
+        }
+        P2("Finished checking alphas, result=%d\n", result);
+    }
+    ret = result;
+    return (ret);
+}
+#endif /* PNGCRUSH_COUNT_COLORS */
+
+
+
+
+
+void print_version_info(void)
+{
+    fprintf(STDERR,
+      "\n"
+      " | pngcrush %s\n"
+      /* If you have modified this source, you may insert additional notices
+       * immediately after this sentence: */
+      " |    Copyright (C) 1998-2002,2006-2009 Glenn Randers-Pehrson\n"
+      " |    Copyright (C) 2005      Greg Roelofs\n"
+      " | This is a free, open-source program.  Permission is irrevocably\n"
+      " | granted to everyone to use this version of pngcrush without\n"
+      " | payment of any fee.\n"
+      " | Executable name is %s\n"
+      " | It was built with libpng version %s, and is\n"
+      " | running with %s"
+      " |    Copyright (C) 1998-2004,2006-2009 Glenn Randers-Pehrson,\n"
+      " |    Copyright (C) 1996, 1997 Andreas Dilger,\n"
+      " |    Copyright (C) 1995, Guy Eric Schalnat, Group 42 Inc.,\n"
+      " | and zlib version %s, Copyright (C) 1998-2002 (or later),\n"
+      " |    Jean-loup Gailly and Mark Adler.\n",
+      PNGCRUSH_VERSION, progname, PNG_LIBPNG_VER_STRING,
+      png_get_header_version(NULL), ZLIB_VERSION);
+
+#if defined(__GNUC__)
+    fprintf(STDERR,
+      " | It was compiled with gcc version %s", __VERSION__);
+#  if defined(PNG_USE_PNGGCCRD)
+    fprintf(STDERR,
+      " and gas version %s", GAS_VERSION);
+#  endif
+#  if defined(__DJGPP__)
+    fprintf(STDERR,
+      "\n"
+      " | under DJGPP %d.%d, Copyright (C) 1995, D. J. Delorie\n"
+      " | and loaded with PMODE/DJ, by Thomas Pytel and Matthias Grimrath\n"
+      " |    Copyright (C) 1996, Matthias Grimrath.\n",
+      __DJGPP__, __DJGPP_MINOR__);
+#  else
+    fprintf(STDERR, ".\n");
+#  endif
+#endif
+
+    fprintf(STDERR, "\n");
+}
+
+
+
+
+
+static const char *pngcrush_legal[] = {
+    "",
+    "If you have modified this source, you may insert additional notices",
+    "immediately after this sentence.",
+    "Copyright (C) 1998-2002,2006-2009 Glenn Randers-Pehrson",
+    "Copyright (C) 2005      Greg Roelofs",
+    "",
+    "DISCLAIMER: The pngcrush computer program is supplied \"AS IS\".",
+    "The Author disclaims all warranties, expressed or implied, including,",
+    "without limitation, the warranties of merchantability and of fitness",
+    "for  any purpose.  The Author assumes no liability for direct, indirect,",
+    "incidental, special, exemplary, or consequential damages, which may",
+    "result from the use of the computer program, even if advised of the",
+    "possibility of such damage.  There is no warranty against interference",
+    "with your enjoyment of the computer program or against infringement.",
+    "There is no warranty that my efforts or the computer program will",
+    "fulfill any of your particular purposes or needs.  This computer",
+    "program is provided with all faults, and the entire risk of satisfactory",
+    "quality, performance, accuracy, and effort is with the user.",
+    "",
+    "LICENSE: Permission is hereby irrevocably granted to everyone to use,",
+    "copy, modify, and distribute this computer program, or portions hereof,",
+    "purpose, without payment of any fee, subject to the following",
+    "restrictions:",
+    "",
+    "1. The origin of this binary or source code must not be misrepresented.",
+    "",
+    "2. Altered versions must be plainly marked as such and must not be",
+    "misrepresented as being the original binary or source.",
+    "",
+    "3. The Copyright notice, disclaimer, and license may not be removed",
+    "or altered from any source, binary, or altered source distribution.",
+    ""
+};
+
+static const char *pngcrush_usage[] = {
+    "\nusage: %s [options] infile.png outfile.png\n",
+    "       %s -e ext [other options] files.png ...\n",
+    "       %s -d dir [other options] files.png ...\n"
+};
+
+struct options_help pngcrush_options[] = {
+    {0, "      -already already_crushed_size [e.g., 8192]"},
+    {2, ""},   /* blank */
+    {2, "               If file has an IDAT greater than this size, it"},
+    {2, "               will be considered to be already crushed and will"},
+    {2, "               not be processed, unless you are making other changes"},
+    {2, "               or the \"-force\" option is present."},
+    {2, ""},
+
+    {0, "    -bit_depth depth (bit_depth to use in output file)"},
+    {2, ""},
+    {2, "               Default output depth is same as input depth."},
+    {2, ""},
+
+#ifdef Z_RLE
+    {0, "        -brute (use brute-force: try 126 different methods [11-136])"},
+#else
+    {0, "        -brute (use brute-force: try 114 different methods [11-124])"},
+#endif
+    {2, ""},
+    {2, "               Very time-consuming and generally not worthwhile."},
+    {2, "               You can restrict this option to certain filter types,"},
+    {2, "               compression levels, or strategies by following it"},
+    {2, "               with \"-f filter\", \"-l level\", or \"-z strategy\"."},
+    {2, ""},
+
+    {0, "            -c color_type of output file [0, 2, 4, or 6]"},
+    {2, ""},
+    {2, "               Color type for the output file.  Future versions"},
+    {2, "               will also allow color_type 3, if there are 256 or"},
+    {2, "               fewer colors present in the input file.  Color types"},
+    {2, "               4 and 6 are padded with an opaque alpha channel if"},
+    {2, "               the input file does not have alpha information."},
+    {2, "               You can use 0 or 4 to convert color to grayscale."},
+    {2, "               Use 0 or 2 to delete an unwanted alpha channel."},
+    {2, "               Default is to use same color type as the input file."},
+    {2, ""},
+
+#ifdef PNGCRUSH_COUNT_COLORS
+    {0, "           -cc (do color counting)"},
+    {2, ""},
+#endif
+
+    {0, "            -d directory_name (where output files will go)"},
+    {2, ""},
+    {2, "               If a directory name is given, then the output"},
+    {2, "               files are placed in it, with the same filenames as"},
+    {2, "               those of the original files. For example,"},
+    {2, "               you would type 'pngcrush -directory CRUSHED *.png'"},
+    {2, "               to get *.png => CRUSHED/*.png"},
+    {2, ""},
+
+    {0, FAKE_PAUSE_STRING},
+
+    {0, " -double_gamma (used for fixing gamma in PhotoShop 5.0/5.02 files)"},
+    {2, ""},
+    {2, "               It has been claimed that the PS5 bug is actually"},
+    {2, "               more complex than that, in some unspecified way."},
+    {2, ""},
+
+    {0, "            -e extension  (used for creating output filename)"},
+    {2, ""},
+    {2, "               e.g., -ext .new means *.png => *.new"},
+    {2, "               and -e _C.png means *.png => *_C.png"},
+    {2, ""},
+
+    {0, "            -f user_filter [0-5]"},
+    {2, ""},
+    {2, "               filter to use with the method specified in the"},
+    {2, "               preceding '-m method' or '-brute_force' argument."},
+    {2, "               0: none; 1-4: use specified filter; 5: adaptive."},
+    {2, ""},
+
+    {0, "          -fix (fix otherwise fatal conditions such as bad CRCs)"},
+    {2, ""},
+
+    {0, "        -force (write a new output file even if larger than input)"},
+    {2, ""},
+    {2, "               Otherwise the input file will be copied to output"},
+    {2, "               if it is smaller than any generated file and no chunk"},
+    {2, "               additions, removals, or changes were requested."},
+    {2, ""},
+
+#ifdef PNG_FIXED_POINT_SUPPORTED
+    {0, "            -g gamma (float or fixed*100000, e.g., 0.45455 or 45455)"},
+#else
+    {0, "            -g gamma (float, e.g., 0.45455)"},
+#endif
+    {2, ""},
+    {2, "               Value to insert in gAMA chunk, only if the input"},
+    {2, "               file has no gAMA chunk.  To replace an existing"},
+    {2, "               gAMA chunk, use the '-replace_gamma' option."},
+    {2, ""},
+
+    {0, FAKE_PAUSE_STRING},
+
+    {0, "      -huffman (use only zlib strategy 2, Huffman-only)"},
+    {2, ""},
+    {2, "               Fast, but almost never very effective except for"},
+    {2, "               certain rare image types."},
+    {2, ""},
+
+#ifdef PNG_iCCP_SUPPORTED
+    {0, "         -iccp length \"Profile Name\" iccp_file"},
+    {2, ""},
+    {2, "               file with ICC profile to insert in an iCCP chunk."},
+    {2, ""},
+#endif
+
+#ifdef PNG_iTXt_SUPPORTED
+    {0, "         -itxt b[efore_IDAT]|a[fter_IDAT] \"keyword\""},
+    {2, "               \"language_code\" \"translated_keyword\" \"text\""},
+    {2, ""},
+    {2, "               Uncompressed iTXt chunk to insert (see -text)."},
+    {2, ""},
+#endif
+
+    {0, "         -keep chunk_name"},
+    {2, ""},
+    {2, "               keep named chunk even when pngcrush makes"},
+    {2, "               changes to the PNG datastream that cause it"},
+    {2, "               to become invalid.  Currently only dSIG is"},
+    {2, "               recognized as a chunk to be kept."},
+    {2, ""},
+
+
+    {0, "            -l zlib_compression_level [0-9]"},
+    {2, ""},
+    {2, "               zlib compression level to use with method specified"},
+    {2, "               with the preceding '-m method' or '-brute_force'"},
+    {2, "               argument."},
+    {2, ""},
+
+#ifdef PNGCRUSH_LOCO
+    {0, "         -loco (\"loco crush\" truecolor PNGs)"},
+    {2, ""},
+    {2, "               Make the file more compressible by performing a"},
+    {2, "               lossless, reversible, color transformation."},
+    {2, "               The resulting file is a MNG, not a PNG, and should"},
+    {2, "               be given the \".mng\" file extension.  The"},
+    {2, "               \"loco\" option has no effect on grayscale or"},
+    {2, "               indexed-color PNG files."},
+    {2, ""},
+#endif
+
+    {0, "            -m method [0 through " STRNGIFY(MAX_METHODS) "]"},
+    {2, ""},
+    {2, "               pngcrush method to try (0 means try all of 1-10)."},
+    {2, "               Can be repeated as in '-m 1 -m 4 -m 7'."},
+    {2, "               This can be useful if pngcrush runs out of memory"},
+    {2, "               when it tries methods 2, 3, 5, 6, 8, 9, or 10 which"},
+    {2, "               use filtering and are memory-intensive.  Methods"},
+    {2, "               1, 4, and 7 use no filtering; methods 11 and up use"},
+    {2, "               specified filter, compression level, and strategy."},
+    {2, ""},
+    {2, FAKE_PAUSE_STRING},
+
+    {0, "          -max maximum_IDAT_size [default "STRNGIFY(PNG_ZBUF_SIZE)"]"},
+    {2, ""},
+
+#ifdef PNGCRUSH_LOCO
+    {0, "          -mng (write a new MNG, do not crush embedded PNGs)"},
+    {2, ""},
+#endif
+
+    {0, " -newtimestamp"},
+    {2, ""},
+    {2, "               Reset file modification time [default]."},
+    {2, ""},
+
+#ifdef PNGCRUSH_COUNT_COLORS
+    {0, "        -no_cc (no color counting)"},
+    {2, ""},
+#endif
+
+    {0, "  -nofilecheck (do not check for infile.png == outfile.png)"},
+    {2, ""},
+    {2, "               To avoid false hits from MSVC-compiled code.  Note"},
+    {2, "               that if you use this option, you are responsible for"},
+    {2, "               ensuring that the input file is not the output file."},
+    {2, ""},
+
+
+    {0, " -oldtimestamp"},
+    {2, ""},
+    {2, "               Don't reset file modification time."},
+    {2, ""},
+
+    {0, "            -n (no save; doesn't do compression or write output PNG)"},
+    {2, ""},
+    {2, "               Useful in conjunction with -v option to get info."},
+    {2, ""},
+
+    {0, "     -plte_len n (truncate PLTE)"},
+    {2, ""},
+    {2, "               Truncates the PLTE.  Be sure not to truncate it to"},
+    {2, "               less than the greatest index present in IDAT."},
+    {2, ""},
+
+    {0, "            -q (quiet)"},
+    {2, ""},
+
+    {0, "       -reduce (do lossless color-type or bit-depth reduction)"},
+    {2, ""},
+    {2, "               (if possible)"},
+    {2, ""},
+
+    {0, "          -rem chunkname (or \"alla\" or \"allb\")"},
+    {2, ""},
+    {2, "               Name of an ancillary chunk or optional PLTE to be"},
+    {2, "               removed.  Be careful with this.  Don't use this"},
+    {2, "               feature to remove transparency, gamma, copyright,"},
+    {2, "               or other valuable information.  To remove several"},
+    {2, "               different chunks, repeat: -rem tEXt -rem pHYs."},
+    {2, "               Known chunks (those in the PNG 1.1 spec or extensions"},
+    {2, "               document) can be named with all lower-case letters,"},
+    {2, "               so \"-rem bkgd\" is equivalent to \"-rem bKGD\".  But"},
+    {2, "               note: \"-rem text\" removes all forms of text chunks;"},
+    {2, "               Exact case is required to remove unknown chunks."},
+    {2, "               To do surgery with a chain-saw, \"-rem alla\" removes"},
+    {2, "               all known ancillary chunks except for tRNS, and"},
+    {2, "               \"-rem allb\" removes all but tRNS and gAMA."},
+    {2, ""},
+
+    {0, FAKE_PAUSE_STRING},
+
+#ifdef PNG_FIXED_POINT_SUPPORTED
+    {0, "-replace_gamma gamma (float or fixed*100000) even if it is present."},
+#else
+    {0, "-replace_gamma gamma (float, e.g. 0.45455) even if it is present."},
+#endif
+    {2, ""},
+
+    {0, "          -res dpi"},
+    {2, ""},
+    {2, "               Write a pHYs chunk with the given resolution."},
+    {2, ""},
+
+#ifdef Z_RLE
+    {0, "          -rle (use only zlib strategy 3, RLE-only)"},
+    {2, ""},
+    {2, "               A relatively fast subset of the \"-brute\" methods,"},
+    {2, "               generally more effective than \"-huffman\" on PNG,"},
+    {2, "               images (and quite effective on black-and-white"},
+    {2, "               images) but not necessarily worth the bother"},
+    {2, "               otherwise."},
+    {2, ""},
+#endif
+
+    {0, "         -save (keep all copy-unsafe chunks)"},
+    {2, ""},
+    {2, "               Save otherwise unknown ancillary chunks that would"},
+    {2, "               be considered copy-unsafe.  This option makes"},
+    {2, "               chunks 'known' to pngcrush, so they can be copied."},
+    {2, "               It also causes the dSIG chunk to be saved, even when"},
+    {2, "               it becomes invalid due to datastream changes."},
+    {2, ""},
+
+    {0, FAKE_PAUSE_STRING},
+
+    {0, "         -srgb [0, 1, 2, or 3]"},
+    {2, ""},
+    {2, "               Value of 'rendering intent' for sRGB chunk."},
+    {2, ""},
+
+    {0, "         -ster [0 or 1]"},
+    {2, ""},
+    {2, "               Value of 'stereo mode' for sTER chunk."},
+    {2, "               0: cross-fused; 1: divergent-fused"},
+    {2, ""},
+
+    {0, "         -text b[efore_IDAT]|a[fter_IDAT] \"keyword\" \"text\""},
+    {2, ""},
+    {2, "               tEXt chunk to insert.  keyword < 80 chars,"},
+    {2, "               text < 2048 chars. For now, you can add no more than"},
+    {2, "               ten tEXt, iTXt, or zTXt chunks per pngcrush run."},
+    {2, ""},
+
+#ifdef PNG_tRNS_SUPPORTED
+    {0, "   -trns_array n trns[0] trns[1] .. trns[n-1]"},
+    {2, ""},
+    {2, "               Insert a tRNS chunk, if no tRNS chunk found in file."},
+    {2, "               Values are for the tRNS array in indexed-color PNG."},
+    {2, ""},
+
+    {0, "         -trns index red green blue gray"},
+    {2, ""},
+    {2, "               Insert a tRNS chunk, if no tRNS chunk found in file."},
+    {2, "               You must give all five parameters regardless of the"},
+    {2, "               color type, scaled to the output bit depth."},
+    {2, ""},
+#endif
+
+    {0, "            -v (display more detailed information)"},
+    {2, ""},
+    {2, "               Repeat the option (use \"-v -v\") for even more."},
+    {2, ""},
+
+    {0, "      -version (display the pngcrush version)"},
+    {2, ""},
+    {2, "               Look for the most recent version of pngcrush at"},
+    {2, "               http://pmt.sf.net"},
+    {2, ""},
+
+    {0, "            -w compression_window_size [32, 16, 8, 4, 2, 1, 512]"},
+    {2, ""},
+    {2, "               Size of the sliding compression window, in kbytes"},
+    {2, "               (or bytes, in case of 512).  It's best to"},
+    {2, "               use the default (32) unless you run out of memory."},
+    {2, "               The program will use a smaller window anyway when"},
+    {2, "               the uncompressed file is smaller than 16k."},
+    {2, ""},
+
+#ifdef Z_RLE
+    {0, "            -z zlib_strategy [0, 1, 2, or 3]"},
+#else
+    {0, "            -z zlib_strategy [0, 1, or 2]"},
+#endif
+    {2, ""},
+    {2, "               zlib compression strategy to use with the preceding"},
+    {2, "               '-m method' argument."},
+    {2, ""},
+
+    {0, "         -zmem zlib_compression_mem_level [1-9, default 9]"},
+    {2, ""},
+
+#ifdef PNG_iTXt_SUPPORTED
+    {0, "        -zitxt b[efore_IDAT]|a[fter_IDAT] \"keyword\""},
+    {2, "               \"language_code\" \"translated_keyword\" \"text\""},
+    {2, ""},
+    {2, "               Compressed iTXt chunk to insert (see -text)."},
+    {2, ""},
+#endif
+
+    {0, "         -ztxt b[efore_IDAT]|a[fter_IDAT] \"keyword\" \"text\""},
+    {2, ""},
+    {2, "               zTXt chunk to insert (see -text)."},
+    {2, ""},
+    {2, FAKE_PAUSE_STRING},
+
+    {0, "            -h (help and legal notices)"},
+    {2, ""},
+    {2, "               Display this information."},
+    {2, ""},
+
+    {0, "            -p (pause)"}
+};
+
+
+
+
+
+void print_usage(int retval)
+{
+    int j, jmax;
+
+    if (verbose) {
+        jmax = sizeof(pngcrush_legal) / sizeof(char *);
+        for (j = 0;  j < jmax;  ++j)
+            fprintf(STDERR, "%s\n", pngcrush_legal[j]);
+
+        jmax = sizeof(pngcrush_usage) / sizeof(char *);
+        for (j = 0;  j < jmax;  ++j)
+            fprintf(STDERR, pngcrush_usage[j], progname);  /* special case */
+    }
+
+    /* this block is also handled specially due to the "else" clause... */
+    if (verbose > 1) {
+        png_crush_pause();
+        fprintf(STDERR,
+          "\n"
+          "options (Note: any option can be spelled out for clarity, e.g.,\n"
+          "          \"pngcrush -dir New -method 7 -remove bkgd *.png\"\n"
+          "          is the same as \"pngcrush -d New -m 7 -rem bkgd *.png\"):"
+          "\n\n");
+    } else
+        fprintf(STDERR, "options:\n");
+
+    /* this is the main part of the help screen; it is more complex than the
+     * other blocks due to the mix of verbose and non-verbose lines */
+    jmax = sizeof(pngcrush_options) / sizeof(struct options_help);
+    for (j = 0;  j < jmax;  ++j) {
+        if (verbose >= pngcrush_options[j].verbosity) {
+            if (pngcrush_options[j].textline[0] == FAKE_PAUSE_STRING[0])
+                png_crush_pause();
+            else
+                fprintf(STDERR, "%s\n", pngcrush_options[j].textline);
+        }
+    }
+
+    /* due to progname, the verbose part of the -p option is handled explicitly
+     * (fortunately, it's the very last option anyway) */
+    if (verbose > 1) {
+        fprintf(STDERR, "\n"
+          "               Wait for [enter] key before continuing display.\n"
+          "               e.g., type '%s -pause -help', if the help\n"
+          "               screen scrolls out of sight.\n\n", progname);
+    }
+
+    exit(retval);
+}
+
+ diff --git a/ChangeLog.txt b/ChangeLog.txt deleted file mode 100644 index 1058fc850..000000000 --- a/ChangeLog.txt +++ /dev/null @@ -1,425 +0,0 @@ - -Change log: - -Version 1.6.18 (built with libpng-1.2.36 and zlib-1.2.3.2) - -Version 1.6.17 (built with libpng-1.2.36 and zlib-1.2.3.2) - Defined TOO_FAR == 32767 in deflate.c (again). The definition - has continually been inadvertently omitted during zlib updates - since pngcrush version 1.6.4. - Revised handling of xcode files so at least we can get printout - of IHDR values with "pngcrush -fix -n -v xcode.png". - Moved ChangeLog.txt back into pngcrush.c so it does not get lost. - Removed single quotes from the ChangeLog. - -Version 1.6.16 (built with libpng-1.2.35 and zlib-1.2.3.2) - Added -newtimestamp and -oldtimestamp options and changed - default condition to timestamping the output file with - the current time (i.e., -newtimestamp is default) - If the -oldtimestamp option is used then the output file - has the same timestamp as the input file. - Added CgBI chunk detection. - -Version 1.6.15 (built with libpng-1.2.35 and zlib-1.2.3.2) - Fixes some missing typecasts on png_malloc() calls, patch from - an anonymous reporter to the SourceForge bug tracker. - Added -time_stamp option to change time stamping from default - condition. - -Version 1.6.14 (built with libpng-1.2.35 and zlib-1.2.3.2) - Avoids CVE-2009-0040. - -Version 1.6.12 (built with libpng-1.2.34 and zlib-1.2.3.2) - -Version 1.6.11 (built with libpng-1.2.33 and zlib-1.2.3.2) - Eliminated a memory leak in libpng with writing bad tEXt chunks. - -Version 1.6.10 (built with libpng-1.2.31 and zlib-1.2.3.2) - Add sTER chunk support. - -Version 1.6.9 (built with libpng-1.2.31 and zlib-1.2.3.2) - Updated cexcept.h to version 2.0.1 - Add missing curly brackets. - -Version 1.6.8 (built with libpng-1.2.29 and zlib-1.2.3.2) - Fixed bug with handling of -z and -zi options. - -Version 1.6.7 (built with libpng-1.2.29 and zlib-1.2.3.2) - Moved PNG_UINT_CHNK and some other defines from pngcrush.h to pngcrush.c - Reject invalid color_type or bit_depth. - -Version 1.6.6 (built with libpng-1.2.29 and zlib-1.2.3.2) - Added dSIG support. Pngcrush will not rewrite an image containing - a dSIG chunk immediately following the IHDR chunk, unless the - dSIG is explicitly removed with "-rem dSIG" or explicitly kept - with "-keep dSIG". In the latter case the saved dSIG chunks will - become invalid if any changes are made to the datastream. - - Fixed bug in writing unknown chunks from the end_info_ptr. - -Version 1.6.5 (built with libpng-1.2.29 and zlib-1.2.3.2) - Discontinued adding a new gAMA chunk when writing sRGB chunk. - -Version 1.6.4 (built with libpng-1.2.9rc1 and zlib-1.2.3) - Fixed bug in handling of undocumented -trns_a option (Michal Politowski). - Fixed bug with "nosave" handling of unknown chunks. - -Version 1.6.3 (built with libpng-1.2.9beta11 and zlib-1.2.3) - - Fixed documentation of iTXt input (Shlomi Tal). - Removed #define PNG_INTERNAL and provided prototypes for some - internal libpng functions that are duplicated in pngcrush.c - -Version 1.6.2 (built with libpng-1.2.8 and zlib-1.2.3) - - Fixed bug with "PNG_ROWBYTES" usage, introduced in version 1.6.0. - The bug could cause a crash and only affects the "nolib" builds. - - Converted C++ style (// ...) comments to C style (/* ... */). - - Defined TOO_FAR == 32767 in deflate.c (again). The definition was - omitted from version 1.6.0 when zlib was upgraded to version 1.2.3. - -Version 1.6.1 (distributed as 1.6.0, built with libpng-1.2.8 and zlib-1.2.3) - - Copied non-exported libpng functions from libpng into pngcrush, to make - pngcrush play more nicely with shared libpng. These are not compiled - when a static library is being built with the bundled libpng and - pngcrush.h is included. - -Version 1.6.0-grr (built with libpng-1.2.4 and zlib-1.1.4pc or zlib-1.2.2) - - Moved ChangeLog out of pngcrush.c comments and into a separate file. - - Filtered pngcrush.c through "indent -kr" and "expand" for readability. - - Moved 550 lines of usage/help/copyright/license/version info to separate - function(s) and cleaned up significantly. - - Added some comments for ease of navigation and readability. - - Stripped out a bunch of ancient-libpng compatibility stuff. - - Defined PNG_UINT_* macros (pngcrush.h for now). - - Fixed unknown-chunk handling ("-rem alla" and "-rem gifx" now work). - - Created modified version of makefile that supports external zlib. - - Added support for methods using Z_RLE zlib strategy (zlib 1.2.x only). - - Documented -huffman option in usage screen. - - Added IDAT statistics to final per-file summary. - - Added utime() support to give output files same timestamps as input files. - -Version 1.5.10 (built with libpng-1.2.4 and zlib-1.1.4pc) - - Fixed bug, introduced in 1.5.9, that caused defaults for method 0 to - be used instead of copying the original image, when the original was - already smallest. - -Version 1.5.9 (built with libpng-1.2.4beta3 and zlib-1.1.4pc) - - Work around CPU timer wraparound at 2G microseconds. - - Upgraded zlib from 1.1.3 to 1.1.4. Pngcrush is believed not to - be vulnerable to the zlib-1.1.3 buffer-overflow bug. - - Choose the first instance of smallest IDAT instead of the last, - for faster final recompression, suggested by TSamuel. - -Version 1.5.8 (built with libpng-1.2.1) - - Added -trns_a option for entering a tRNS array. - -Version 1.5.7 (built with libpng-1.2.0) - - Added setargv.obj to Makefile.msc to expand wildcards, e.g., *.png - - Use constant string "pngcrush" instead of argv[0] when appropriate. - - Only check stats for infile==outfile once per input file, or not at all - if "-nofilecheck" option is present or if a directory was created. - - Fixed bugs with changing bit_depth of grayscale images. - -Version 1.5.6 (built with libpng-1.0.12) - - Eliminated extra "Removed the cHNK chunk" messages generated by version - 1.5.5 when "-rem alla" or "-rem allb" is used. - - All unknown chunks including safe-to-copy chunks are now removed in - response to the "-rem alla" or "-rem allb" options. - - Issue a warning if the user tries "-cc" option when it is not supported. - -Version 1.5.5 (built with libpng-1.0.12) - - Reset reduce_to_gray and it_is_opaque flags prior to processing each - image. - - Enable removal of safe-to-copy chunks that are being handled as unknown - e.g., "-rem time". - -Version 1.5.4 (built with libpng-1.0.11) - - Added 262 to the length of uncompressed data when calculating - required_window_size, to account for zlib/deflate implementation. - - Added "-bit_depth n" to the help screen. - - Call png_set_packing() when increasing bit_depth to 2 or 4. - - Added warning about not overwriting an existing tRNS chunk. - - Reduced the memory usage - - Write 500K IDAT chunks even when system libpng is being used. - - Ignore all-zero cHRM chunks, with a warning. - -Version 1.5.3 (built with libpng-1.0.9beta5) - - Added "-loco" option (writes MNG files with filter_method 64) - - "-dir" and "-ext" options are no longer mutually exclusive, e.g.: - pngcrush -loco -dir Crushed -ext .mng *.png - -Version 1.5.2 (built with libpng-1.0.9beta1) - - Added "-iccp" option. - - Increased the zlib memory level, which improves compression (typically - about 1.3 percent for photos) at the expense of increased memory usage. - - Enabled the "-max max_idat_size" option, even when max_idat_size - exceeds the default 1/2 megabyte size. - - Added missing "png_ptr" argument to png_error() call - - Added "-loco" option, to enable the LOCO color transformation - (R->R-G, G, B->B-G) while writing a MNG with filter_method 64. Undo - the transformation and write the regular PNG filter_method (0) if the - MNG filter_method 64 is detected. - - Revised the "-help" output slightly and improved the "-version" output. - - The "-already[_crushed]" option is now ignored if the "-force" option - is present or if chunks are being added, deleted, or modified. - - Improved "things_have_changed" behavior (now, when set in a particular - file, it is not set for all remaining files) - -Version 1.5.1 (built with libpng-1.0.8) - - Disabled color counting by default and made it controllable with new - -cc and -no_cc commandline arguments. - - Added some #ifdef PNGCRUSH_COUNT_COLORS around code that needs it. - - Revised count_colors() attempting to avoid stack corruption that has - been observed on RedHat 6.2 - - Added the word "irrevocably" to the license and changed "without fee" - to "without payment of any fee". - -Version 1.5.0 (built with libpng-1.0.8) - - After encountering an image with a bad Photoshop iCCP chunk, pngcrush - 1.4.5 through 1.4.8 write sRGB and gAMA=45455 chunks in all - remaining PNG files on the command line. This has been fixed so the - correction is only applied to the particular bad input file. - -Version 1.4.8 (built with libpng-1.0.8rc1) - - Detect and remove all-opaque alpha channel. - Detect and reduce all-gray truecolor images to grayscale. - -Version 1.4.7 (built with libpng-1.0.8rc1) - - Restored the "-ext" option that was inadvertently overridden with - a new "-exit" option in version 1.4.6 ("-exit" is used to force an - "exit" instead of a "return" from the main program). - -Version 1.4.6 (built with libpng-1.0.8rc1) - - Fixed bug in color-counting of noninterlaced images. - - Added capability of processing multiple rows at a time (disabled by - default because it turns out to be no faster). - - Replaced "return" statements in main() with "exit" statements. - Force exit instead of return with "-exit" argument. - - Added the UCITA disclaimers to the help output. - -Version 1.4.5 (built with libpng-1.0.7rc2 and cexcept-1.0.0) - - Added color-counting and palette-building capability (enable by - defining PNGCRUSH_COUNT_COLORS). In a future version, this will - give pngcrush the ability to reduce RGBA images to indexed-color - or grayscale when fewer than 257 RGBA combinations are present, - and no color is present that requires 16-bit precision. For now, - it only reports the frequencies. - - Added "-fix" option, for fixing bad CRCs and other correctable - conditions. - - Write sBIT.alpha=1 when adding an opaque alpha channel and sBIT - is present. - - Identify the erroneous 2615-byte sRGB monitor profile being written - by Photoshop 5.5, which causes many apps to crash, and replace it with - an sRGB chunk. - - Added a check for input and output on different devices before rejecting - the output file as being the same as the input file based on inode. - - Added some UCITA language to the disclaimer. - -Version 1.4.4 (built with libpng-1.0.6i and cexcept-0.6.3) - - Can be built on RISC OS platforms, thanks to Darren Salt. - -Version 1.4.3 (built with libpng-1.0.6h and cexcept-0.6.3) - - Reduced scope of Try/Catch blocks to avoid nesting them, and - removed returns from within the Try blocks, where they are not - allowed. - - Removed direct access to the png structure when possible, and isolated - the remaining direct accesses to the png structure into new - png_get_compression_buffer_size(), png_set_compression_buffer_size(), - and png_set_unknown_chunk_location() functions that were installed - in libpng version 1.0.6g. - -Version 1.4.2 (built with libpng-1.0.6f and cexcept-0.6.0) - - Removes extra IDAT chunks (such as found in some POV-ray PNGs) with - a warning instead of bailing out (this feature requires libpng-1.0.6f - or later, compiled with "#define PNG_ABORT()"). - - Removed old setjmp interface entirely. - -Version 1.4.1 (built with libpng-1.0.6e and cexcept-0.6.0) - - Uses cexcept.h for error handling instead of libpngs built-in - setjmp/longjmp mechanism. See http://cexcept.sf.net/ - - Pngcrush.c will now run when compiled with old versions of libpng back - to version 0.96, although some features will not be available. - -Version 1.4.0 (built with libpng-1.0.6 + libpng-1.0.6-patch-a) - -Version 1.3.6 (built with libpng-1.0.5v) - - RGB to Grayscale conversion is more accurate (15-bit instead of 8-bit) - and now uses only integer arithmetic. - - "#ifdefed" out PNG_READ_DITHER - - Changed "Compressed" to "Uncompressed" in help for -itxt. - - Stifled some compiler warnings - -Version 1.3.5 (built with libpng-1.0.5s) - - Add test on stat_buf.st_size to verify fpin==fpout, because stat in - MSVC++6.0 standard version returns stat_buf.st_ino=0 for all files. - - Revised pngcrush.h to make it easier to control PNG_ZBUF_SIZE and - PNG_NO_FLOATING_POINT_SUPPORTED from a makefile. - - Restored ability to enter "replace_gamma" value as a float even when - floating point arithmetic is not enabled. - - Enabled removing tEXt, zTXt, or iTXt chunks by chunk type, i.e., - "-rem tEXt" only removes tEXt chunks, while "-rem text" removes all - three types of text chunk. - - Removed definition of TOO_FAR from pngcrush.h - - Uses new libpng error handler; if a file has errors, pngcrush now will - continue on and compress the remaining files instead of bailing out. - -Version 1.3.4 (built with libpng-1.0.5m) - - Do not allow pngcrush to overwrite the input file. - -Version 1.3.3 (built with libpng-1.0.5m) - - Restored ability to enter gamma as a float even when floating point - arithmetic is not enabled. - -Version 1.3.2 (built with libpng-1.0.5k) - - Renamed "dirname" to "directory_name" to avoid conflict with "dirname" - that appears in string.h on some platforms. - - Fixed "PNG_NO_FLOAING_POINT" typo in pngcrush.h - - "#ifdefed" out parts of the help screen for options that are unsupported. - -Version 1.3.1 (built with libpng-1.0.5k): Eliminated some spurious warnings - that were being issued by libpng-1.0.5j. Added -itxt, -ztxt, and - -zitxt descriptions to the help screen. - - Dropped explicit support for pCAL, hIST, sCAL, sPLT, iCCP, tIME, and - cHRM chunks and handle them as unknown but safe-to-copy instead, using - new png_handle_as_unknown function available in libpng-1.0.5k. - -Version 1.3.0 (built with libpng-1.0.5j): Added support for handling - unknown chunks. - - pngcrush is now fixed-point only, unless PNG_NO_FLOATING_POINT_SUPPORTED - is undefined in pngcrush.h. - - Added support for the iCCP, iTXt, sCAL, and sPLT chunks, which - are now supported by libpng (since libpng-1.0.5j). None of these have - been adequately tested. - - "#ifdefed" out more unused code (weighted filters and progressive read; - this saves about 15k in the size of the executable). - - Moved the special definitions from pngconf.h into a new pngcrush.h - - Disallow 256-byte compression window size when writing, to work around - an apparent zlib bug. Either deflate was producing incorrect results in a - 21x21 4-bit image or inflate was decoding it incorrectly; the uncompressed - stream is 252 bytes, which is uncomfortably close to the resulting - 256-byte compression window. This workaround can be removed when zlib - is fixed. - - The "-m method" can be used any of the 124 methods, without having to - specify the filter, level, and strategy, instead of just the first 10. - -Version 1.2.1 (built with libpng-1.0.5f): Fixed -srgb parameter so it - really does take an argument, and so it continues to use "0" if an - integer does not follow the -srgb. - - Added "-plte_len n" argument for truncating the PLTE. Be sure not to - truncate it to less than the greatest index actually appearing in IDAT. - -Version 1.2.0: Removed registration requirement. Added open source - license. Redefined TOO_FAR=32k in deflate.c. - -Changes prior to going "open source": - -Version 1.1.8: built with libpng-1.0.5a. Runs OK with pngvcrd.c. - -Version 1.1.7: added ability to add tEXt/zTXt chunks. Fixed bug with -closing a file that was not opened when using "pngcrush -n". Fixed -bug with tEXt/zTXt chunks after IDAT not being copied. -Added alpha to the displayed palette table. Rebuilt with libpng-1.0.5. - -Version 1.1.6: fixed bug with one file left open after each image is -processed - -Version 1.1.5: Shorten or remove tRNS chunks that are all opaque or have -opaque entries at the end. Added timing report. - -Version 1.1.4: added ability to restrict brute_force to one or more filter - types, compression levels, or compression strategies. - diff --git a/png.c b/png.c index 33b6df1af..62b86e1d0 100644 --- a/png.c +++ b/png.c @@ -1,7 +1,7 @@ /* png.c - location for general purpose libpng functions * - * Last changed in libpng 1.2.37 [May 27, 2009] + * Last changed in libpng 1.2.37 [June 4, 2009] * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) @@ -13,7 +13,7 @@ #include "png.h" /* Generate a compiler error if there is an old png.h in the search path. */ -typedef version_1_2_37rc01 Your_png_h_is_not_version_1_2_37rc01; +typedef version_1_2_37 Your_png_h_is_not_version_1_2_37; /* Version information for C files. This had better match the version * string defined in png.h. */ @@ -702,7 +702,7 @@ png_charp PNGAPI png_get_copyright(png_structp png_ptr) { png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */ - return ((png_charp) "\n libpng version 1.2.37rc01 - May 27, 2009\n\ + return ((png_charp) "\n libpng version 1.2.37 - June 4, 2009\n\ Copyright (c) 1998-2009 Glenn Randers-Pehrson\n\ Copyright (c) 1996-1997 Andreas Dilger\n\ Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n"); diff --git a/png.h b/png.h index 9b4c4670b..80929899d 100644 --- a/png.h +++ b/png.h @@ -1,6 +1,6 @@ /* png.h - header file for PNG reference library * - * libpng version 1.2.37rc01 - May 27, 2009 + * libpng version 1.2.37 - June 4, 2009 * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -8,7 +8,7 @@ * Authors and maintainers: * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger - * libpng versions 0.97, January 1998, through 1.2.37rc01 - May 27, 2009: Glenn + * libpng versions 0.97, January 1998, through 1.2.37 - June 4, 2009: Glenn * See also "Contributing Authors", below. * * Note about libpng version numbers: @@ -228,6 +228,7 @@ * 1.2.36 13 10236 12.so.0.36[.0] * 1.2.37beta01-03 13 10237 12.so.0.37[.0] * 1.2.37rc01 13 10237 12.so.0.37[.0] + * 1.2.37 13 10237 12.so.0.37[.0] * * Henceforth the source version will match the shared-library major * and minor numbers; the shared-library major version number will be @@ -257,7 +258,7 @@ * If you modify libpng you may insert additional notices immediately following * this sentence. * - * libpng versions 1.2.6, August 15, 2004, through 1.2.37rc01, May 27, 2009, are + * libpng versions 1.2.6, August 15, 2004, through 1.2.37, June 4, 2009, are * Copyright (c) 2004, 2006-2009 Glenn Randers-Pehrson, and are * distributed according to the same disclaimer and license as libpng-1.2.5 * with the following individual added to the list of Contributing Authors: @@ -369,13 +370,13 @@ * Y2K compliance in libpng: * ========================= * - * May 27, 2009 + * June 4, 2009 * * Since the PNG Development group is an ad-hoc body, we can't make * an official declaration. * * This is your unofficial assurance that libpng from version 0.71 and - * upward through 1.2.37rc01 are Y2K compliant. It is my belief that earlier + * upward through 1.2.37 are Y2K compliant. It is my belief that earlier * versions were also Y2K compliant. * * Libpng only has three year fields. One is a 2-byte unsigned integer @@ -431,9 +432,9 @@ */ /* Version information for png.h - this should match the version in png.c */ -#define PNG_LIBPNG_VER_STRING "1.2.37rc01" +#define PNG_LIBPNG_VER_STRING "1.2.37" #define PNG_HEADER_VERSION_STRING \ - " libpng version 1.2.37rc01 - May 27, 2009\n" + " libpng version 1.2.37 - June 4, 2009\n" #define PNG_LIBPNG_VER_SONUM 0 #define PNG_LIBPNG_VER_DLLNUM 13 @@ -445,7 +446,7 @@ /* This should match the numeric part of the final component of * PNG_LIBPNG_VER_STRING, omitting any leading zero: */ -#define PNG_LIBPNG_VER_BUILD 01 +#define PNG_LIBPNG_VER_BUILD 0 /* Release Status */ #define PNG_LIBPNG_BUILD_ALPHA 1 @@ -462,7 +463,7 @@ #define PNG_LIBPNG_BUILD_SPECIAL 32 /* Cannot be OR'ed with PNG_LIBPNG_BUILD_PRIVATE */ -#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_RC +#define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE /* Careful here. At one time, Guy wanted to use 082, but that would be octal. * We must not include leading zeros. @@ -1493,7 +1494,7 @@ struct png_struct_def /* This triggers a compiler error in png.c, if png.c and png.h * do not agree upon the version number. */ -typedef png_structp version_1_2_37rc01; +typedef png_structp version_1_2_37; typedef png_struct FAR * FAR * png_structpp; diff --git a/pngconf.h b/pngconf.h index 8fed45c1a..da8888325 100644 --- a/pngconf.h +++ b/pngconf.h @@ -1,7 +1,7 @@ /* pngconf.h - machine configurable file for libpng * - * libpng version 1.2.37rc01 - May 27, 2009 + * libpng version 1.2.37 - June 4, 2009 * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) diff --git a/pngcrush.c b/pngcrush.c index 820363930..331ab8a39 100644 --- a/pngcrush.c +++ b/pngcrush.c @@ -156,7 +156,7 @@ Change log: -Version 1.6.18 (built with libpng-1.2.37rc01 and zlib-1.2.3.2) +Version 1.6.18 (built with libpng-1.2.37 and zlib-1.2.3.2) Removed extra FCLOSE(fpin) and FCLOSE(fpout) in the first Catch{} block, since they get removed anyway right after that (hanno boeck). Define PNG_NO_READ|WRITE_cHRM and PNG_NO_READ_|WRITEiCCP in pngcrush.h diff --git a/pngerror.c b/pngerror.c index ed4e3f1b3..71a2e53c1 100644 --- a/pngerror.c +++ b/pngerror.c @@ -1,7 +1,7 @@ /* pngerror.c - stub functions for i/o and memory allocation * - * Last changed in libpng 1.2.37 [May 27, 2009] + * Last changed in libpng 1.2.37 [June 4, 2009] * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) diff --git a/pngget.c b/pngget.c index 80a54d055..0022d95f1 100644 --- a/pngget.c +++ b/pngget.c @@ -1,7 +1,7 @@ /* pngget.c - retrieval of values from info struct * - * Last changed in libpng 1.2.37 [May 27, 2009] + * Last changed in libpng 1.2.37 [June 4, 2009] * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) @@ -121,7 +121,8 @@ png_get_x_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) if (info_ptr->phys_unit_type != PNG_RESOLUTION_METER) return (0); - else return (info_ptr->x_pixels_per_unit); + else + return (info_ptr->x_pixels_per_unit); } #else return (0); @@ -141,7 +142,8 @@ png_get_y_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) if (info_ptr->phys_unit_type != PNG_RESOLUTION_METER) return (0); - else return (info_ptr->y_pixels_per_unit); + else + return (info_ptr->y_pixels_per_unit); } #else return (0); @@ -162,7 +164,8 @@ png_get_pixels_per_meter(png_structp png_ptr, png_infop info_ptr) info_ptr->x_pixels_per_unit != info_ptr->y_pixels_per_unit) return (0); - else return (info_ptr->x_pixels_per_unit); + else + return (info_ptr->x_pixels_per_unit); } #else return (0); @@ -206,7 +209,8 @@ png_get_x_offset_microns(png_structp png_ptr, png_infop info_ptr) if (info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER) return (0); - else return (info_ptr->x_offset); + else + return (info_ptr->x_offset); } #else return (0); @@ -227,7 +231,8 @@ png_get_y_offset_microns(png_structp png_ptr, png_infop info_ptr) if (info_ptr->offset_unit_type != PNG_OFFSET_MICROMETER) return (0); - else return (info_ptr->y_offset); + else + return (info_ptr->y_offset); } #else return (0); @@ -248,7 +253,8 @@ png_get_x_offset_pixels(png_structp png_ptr, png_infop info_ptr) if (info_ptr->offset_unit_type != PNG_OFFSET_PIXEL) return (0); - else return (info_ptr->x_offset); + else + return (info_ptr->x_offset); } #else return (0); @@ -269,7 +275,8 @@ png_get_y_offset_pixels(png_structp png_ptr, png_infop info_ptr) if (info_ptr->offset_unit_type != PNG_OFFSET_PIXEL) return (0); - else return (info_ptr->y_offset); + else + return (info_ptr->y_offset); } #else return (0); diff --git a/pngmem.c b/pngmem.c index 18559030f..d1999b657 100644 --- a/pngmem.c +++ b/pngmem.c @@ -1,7 +1,7 @@ /* pngmem.c - stub functions for memory allocation * - * Last changed in libpng 1.2.37 [May 27, 2009] + * Last changed in libpng 1.2.37 [June 4, 2009] * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) diff --git a/pngpread.c b/pngpread.c index f4037c22d..9746c7a06 100644 --- a/pngpread.c +++ b/pngpread.c @@ -1,7 +1,7 @@ /* pngpread.c - read a png file in push mode * - * Last changed in libpng 1.2.37 [May 27, 2009] + * Last changed in libpng 1.2.37 [June 4, 2009] * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) diff --git a/pngread.c b/pngread.c index e2837a8b0..370ecba8e 100644 --- a/pngread.c +++ b/pngread.c @@ -1,7 +1,7 @@ /* pngread.c - read a PNG file * - * Last changed in libpng 1.2.37 [May 27, 2009] + * Last changed in libpng 1.2.37 [June 4, 2009] * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) @@ -192,7 +192,8 @@ png_read_init_2(png_structp png_ptr, png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t png_info_size) { /* We only come here via pre-1.0.12-compiled applications */ - if (png_ptr == NULL) return; + if (png_ptr == NULL) + return; #if !defined(PNG_NO_STDIO) && !defined(_WIN32_WCE) if (png_sizeof(png_struct) > png_struct_size || png_sizeof(png_info) > png_info_size) @@ -246,7 +247,8 @@ png_read_init_3(png_structpp ptr_ptr, png_const_charp user_png_ver, png_structp png_ptr=*ptr_ptr; - if (png_ptr == NULL) return; + if (png_ptr == NULL) + return; do { diff --git a/pngrio.c b/pngrio.c index 7449c9320..2c8e6a741 100644 --- a/pngrio.c +++ b/pngrio.c @@ -1,7 +1,7 @@ /* pngrio.c - functions for data input * - * Last changed in libpng 1.2.37 [May 27, 2009] + * Last changed in libpng 1.2.37 [June 4, 2009] * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) diff --git a/pngrtran.c b/pngrtran.c index 559f5c4aa..af396df07 100644 --- a/pngrtran.c +++ b/pngrtran.c @@ -1,7 +1,7 @@ /* pngrtran.c - transforms the data in a row for PNG readers * - * Last changed in libpng 1.2.37 [May 27, 2009] + * Last changed in libpng 1.2.37 [June 4, 2009] * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) diff --git a/pngrutil.c b/pngrutil.c index 2cfa7a427..ae1e3f78a 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -1,7 +1,7 @@ /* pngrutil.c - utilities to read a PNG file * - * Last changed in libpng 1.2.37 [May 27, 2009] + * Last changed in libpng 1.2.37 [June 4, 2009] * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) diff --git a/pngset.c b/pngset.c index c279df38c..fa68a2dcb 100644 --- a/pngset.c +++ b/pngset.c @@ -1,7 +1,7 @@ /* pngset.c - storage of image information into info struct * - * Last changed in libpng 1.2.37 [May 27, 2009] + * Last changed in libpng 1.2.37 [June 4, 2009] * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) diff --git a/pngtest.c b/pngtest.c deleted file mode 100644 index ba8a2dafd..000000000 --- a/pngtest.c +++ /dev/null @@ -1,1687 +0,0 @@ - -/* pngtest.c - a simple test program to test libpng - * - * Last changed in libpng 1.2.37 [May 27, 2009] - * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2009 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - * - * This program reads in a PNG image, writes it out again, and then - * compares the two files. If the files are identical, this shows that - * the basic chunk handling, filtering, and (de)compression code is working - * properly. It does not currently test all of the transforms, although - * it probably should. - * - * The program will report "FAIL" in certain legitimate cases: - * 1) when the compression level or filter selection method is changed. - * 2) when the maximum IDAT size (PNG_ZBUF_SIZE in pngconf.h) is not 8192. - * 3) unknown unsafe-to-copy ancillary chunks or unknown critical chunks - * exist in the input file. - * 4) others not listed here... - * In these cases, it is best to check with another tool such as "pngcheck" - * to see what the differences between the two files are. - * - * If a filename is given on the command-line, then this file is used - * for the input, rather than the default "pngtest.png". This allows - * testing a wide variety of files easily. You can also test a number - * of files at once by typing "pngtest -m file1.png file2.png ..." - */ - -#include "png.h" - -#if defined(_WIN32_WCE) -# if _WIN32_WCE < 211 - __error__ (f|w)printf functions are not supported on old WindowsCE.; -# endif -# include -# include -# define READFILE(file, data, length, check) \ - if (ReadFile(file, data, length, &check, NULL)) check = 0 -# define WRITEFILE(file, data, length, check)) \ - if (WriteFile(file, data, length, &check, NULL)) check = 0 -# define FCLOSE(file) CloseHandle(file) -#else -# include -# include -# define READFILE(file, data, length, check) \ - check=(png_size_t)fread(data, (png_size_t)1, length, file) -# define WRITEFILE(file, data, length, check) \ - check=(png_size_t)fwrite(data, (png_size_t)1, length, file) -# define FCLOSE(file) fclose(file) -#endif - -#if defined(PNG_NO_STDIO) -# if defined(_WIN32_WCE) - typedef HANDLE png_FILE_p; -# else - typedef FILE * png_FILE_p; -# endif -#endif - -/* Makes pngtest verbose so we can find problems (needs to be before png.h) */ -#ifndef PNG_DEBUG -# define PNG_DEBUG 0 -#endif - -#if !PNG_DEBUG -# define SINGLE_ROWBUF_ALLOC /* Makes buffer overruns easier to nail */ -#endif - -/* Turn on CPU timing -#define PNGTEST_TIMING -*/ - -#ifdef PNG_NO_FLOATING_POINT_SUPPORTED -#undef PNGTEST_TIMING -#endif - -#ifdef PNGTEST_TIMING -static float t_start, t_stop, t_decode, t_encode, t_misc; -#include -#endif - -#if defined(PNG_TIME_RFC1123_SUPPORTED) -#define PNG_tIME_STRING_LENGTH 29 -static int tIME_chunk_present = 0; -static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present"; -#endif - -static int verbose = 0; - -int test_one_file PNGARG((PNG_CONST char *inname, PNG_CONST char *outname)); - -#ifdef __TURBOC__ -#include -#endif - -/* Defined so I can write to a file on gui/windowing platforms */ -/* #define STDERR stderr */ -#define STDERR stdout /* For DOS */ - -/* In case a system header (e.g., on AIX) defined jmpbuf */ -#ifdef jmpbuf -# undef jmpbuf -#endif - -/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */ -#ifndef png_jmpbuf -# define png_jmpbuf(png_ptr) png_ptr->jmpbuf -#endif - -/* Example of using row callbacks to make a simple progress meter */ -static int status_pass = 1; -static int status_dots_requested = 0; -static int status_dots = 1; - -void -#ifdef PNG_1_0_X -PNGAPI -#endif -read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); -void -#ifdef PNG_1_0_X -PNGAPI -#endif -read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) -{ - if (png_ptr == NULL || row_number > PNG_UINT_31_MAX) - return; - if (status_pass != pass) - { - fprintf(stdout, "\n Pass %d: ", pass); - status_pass = pass; - status_dots = 31; - } - status_dots--; - if (status_dots == 0) - { - fprintf(stdout, "\n "); - status_dots=30; - } - fprintf(stdout, "r"); -} - -void -#ifdef PNG_1_0_X -PNGAPI -#endif -write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass); -void -#ifdef PNG_1_0_X -PNGAPI -#endif -write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) -{ - if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) - return; - fprintf(stdout, "w"); -} - - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) -/* Example of using user transform callback (we don't transform anything, - * but merely examine the row filters. We set this to 256 rather than - * 5 in case illegal filter values are present.) - */ -static png_uint_32 filters_used[256]; -void -#ifdef PNG_1_0_X -PNGAPI -#endif -count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data); -void -#ifdef PNG_1_0_X -PNGAPI -#endif -count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data) -{ - if (png_ptr != NULL && row_info != NULL) - ++filters_used[*(data - 1)]; -} -#endif - -#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) -/* Example of using user transform callback (we don't transform anything, - * but merely count the zero samples) - */ - -static png_uint_32 zero_samples; - -void -#ifdef PNG_1_0_X -PNGAPI -#endif -count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data); -void -#ifdef PNG_1_0_X -PNGAPI -#endif -count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data) -{ - png_bytep dp = data; - if (png_ptr == NULL)return; - - /* Contents of row_info: - * png_uint_32 width width of row - * png_uint_32 rowbytes number of bytes in row - * png_byte color_type color type of pixels - * png_byte bit_depth bit depth of samples - * png_byte channels number of channels (1-4) - * png_byte pixel_depth bits per pixel (depth*channels) - */ - - /* Counts the number of zero samples (or zero pixels if color_type is 3 */ - - if (row_info->color_type == 0 || row_info->color_type == 3) - { - int pos = 0; - png_uint_32 n, nstop; - for (n = 0, nstop=row_info->width; nbit_depth == 1) - { - if (((*dp << pos++ ) & 0x80) == 0) - zero_samples++; - if (pos == 8) - { - pos = 0; - dp++; - } - } - if (row_info->bit_depth == 2) - { - if (((*dp << (pos+=2)) & 0xc0) == 0) - zero_samples++; - if (pos == 8) - { - pos = 0; - dp++; - } - } - if (row_info->bit_depth == 4) - { - if (((*dp << (pos+=4)) & 0xf0) == 0) - zero_samples++; - if (pos == 8) - { - pos = 0; - dp++; - } - } - if (row_info->bit_depth == 8) - if (*dp++ == 0) - zero_samples++; - if (row_info->bit_depth == 16) - { - if ((*dp | *(dp+1)) == 0) zero_samples++; - dp+=2; - } - } - } - else /* Other color types */ - { - png_uint_32 n, nstop; - int channel; - int color_channels = row_info->channels; - if (row_info->color_type > 3)color_channels--; - - for (n = 0, nstop=row_info->width; nbit_depth == 8) - if (*dp++ == 0) - zero_samples++; - if (row_info->bit_depth == 16) - { - if ((*dp | *(dp+1)) == 0) zero_samples++; - dp+=2; - } - } - if (row_info->color_type > 3) - { - dp++; - if (row_info->bit_depth == 16) - dp++; - } - } - } -} -#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */ - -static int wrote_question = 0; - -#if defined(PNG_NO_STDIO) -/* START of code to validate stdio-free compilation */ -/* These copies of the default read/write functions come from pngrio.c and - * pngwio.c. They allow "don't include stdio" testing of the library. - * This is the function that does the actual reading of data. If you are - * not reading from a standard C stream, you should create a replacement - * read_data function and use it at run time with png_set_read_fn(), rather - * than changing the library. - */ - -#ifndef USE_FAR_KEYWORD -static void -pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_size_t check; - - /* fread() returns 0 on error, so it is OK to store this in a png_size_t - * instead of an int, which is what fread() actually returns. - */ - READFILE((png_FILE_p)png_ptr->io_ptr, data, length, check); - - if (check != length) - { - png_error(png_ptr, "Read Error!"); - } -} -#else -/* This is the model-independent version. Since the standard I/O library - can't handle far buffers in the medium and small models, we have to copy - the data. -*/ - -#define NEAR_BUF_SIZE 1024 -#define MIN(a,b) (a <= b ? a : b) - -static void -pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - int check; - png_byte *n_data; - png_FILE_p io_ptr; - - /* Check if data really is near. If so, use usual code. */ - n_data = (png_byte *)CVT_PTR_NOCHECK(data); - io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); - if ((png_bytep)n_data == data) - { - READFILE(io_ptr, n_data, length, check); - } - else - { - png_byte buf[NEAR_BUF_SIZE]; - png_size_t read, remaining, err; - check = 0; - remaining = length; - do - { - read = MIN(NEAR_BUF_SIZE, remaining); - READFILE(io_ptr, buf, 1, err); - png_memcpy(data, buf, read); /* Copy far buffer to near buffer */ - if (err != read) - break; - else - check += err; - data += read; - remaining -= read; - } - while (remaining != 0); - } - if (check != length) - png_error(png_ptr, "read Error"); -} -#endif /* USE_FAR_KEYWORD */ - -#if defined(PNG_WRITE_FLUSH_SUPPORTED) -static void -pngtest_flush(png_structp png_ptr) -{ - /* Do nothing; fflush() is said to be just a waste of energy. */ - png_ptr = png_ptr; /* Stifle compiler warning */ -} -#endif - -/* This is the function that does the actual writing of data. If you are - * not writing to a standard C stream, you should create a replacement - * write_data function and use it at run time with png_set_write_fn(), rather - * than changing the library. - */ -#ifndef USE_FAR_KEYWORD -static void -pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_uint_32 check; - - WRITEFILE((png_FILE_p)png_ptr->io_ptr, data, length, check); - if (check != length) - { - png_error(png_ptr, "Write Error"); - } -} -#else -/* This is the model-independent version. Since the standard I/O library - can't handle far buffers in the medium and small models, we have to copy - the data. -*/ - -#define NEAR_BUF_SIZE 1024 -#define MIN(a,b) (a <= b ? a : b) - -static void -pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) -{ - png_uint_32 check; - png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ - png_FILE_p io_ptr; - - /* Check if data really is near. If so, use usual code. */ - near_data = (png_byte *)CVT_PTR_NOCHECK(data); - io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); - if ((png_bytep)near_data == data) - { - WRITEFILE(io_ptr, near_data, length, check); - } - else - { - png_byte buf[NEAR_BUF_SIZE]; - png_size_t written, remaining, err; - check = 0; - remaining = length; - do - { - written = MIN(NEAR_BUF_SIZE, remaining); - png_memcpy(buf, data, written); /* Copy far buffer to near buffer */ - WRITEFILE(io_ptr, buf, written, err); - if (err != written) - break; - else - check += err; - data += written; - remaining -= written; - } - while (remaining != 0); - } - if (check != length) - { - png_error(png_ptr, "Write Error"); - } -} -#endif /* USE_FAR_KEYWORD */ - -/* This function is called when there is a warning, but the library thinks - * it can continue anyway. Replacement functions don't have to do anything - * here if you don't want to. In the default configuration, png_ptr is - * not used, but it is passed in case it may be useful. - */ -static void -pngtest_warning(png_structp png_ptr, png_const_charp message) -{ - PNG_CONST char *name = "UNKNOWN (ERROR!)"; - if (png_ptr != NULL && png_ptr->error_ptr != NULL) - name = png_ptr->error_ptr; - fprintf(STDERR, "%s: libpng warning: %s\n", name, message); -} - -/* This is the default error handling function. Note that replacements for - * this function MUST NOT RETURN, or the program will likely crash. This - * function is used by default, or if the program supplies NULL for the - * error function pointer in png_set_error_fn(). - */ -static void -pngtest_error(png_structp png_ptr, png_const_charp message) -{ - pngtest_warning(png_ptr, message); - /* We can return because png_error calls the default handler, which is - * actually OK in this case. - */ -} -#endif /* PNG_NO_STDIO */ -/* END of code to validate stdio-free compilation */ - -/* START of code to validate memory allocation and deallocation */ -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - -/* Allocate memory. For reasonable files, size should never exceed - * 64K. However, zlib may allocate more then 64K if you don't tell - * it not to. See zconf.h and png.h for more information. zlib does - * need to allocate exactly 64K, so whatever you call here must - * have the ability to do that. - * - * This piece of code can be compiled to validate max 64K allocations - * by setting MAXSEG_64K in zlib zconf.h *or* PNG_MAX_MALLOC_64K. - */ -typedef struct memory_information -{ - png_uint_32 size; - png_voidp pointer; - struct memory_information FAR *next; -} memory_information; -typedef memory_information FAR *memory_infop; - -static memory_infop pinformation = NULL; -static int current_allocation = 0; -static int maximum_allocation = 0; -static int total_allocation = 0; -static int num_allocations = 0; - -png_voidp png_debug_malloc PNGARG((png_structp png_ptr, png_uint_32 size)); -void png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr)); - -png_voidp -png_debug_malloc(png_structp png_ptr, png_uint_32 size) -{ - - /* png_malloc has already tested for NULL; png_create_struct calls - * png_debug_malloc directly, with png_ptr == NULL which is OK - */ - - if (size == 0) - return (NULL); - - /* This calls the library allocator twice, once to get the requested - buffer and once to get a new free list entry. */ - { - /* Disable malloc_fn and free_fn */ - memory_infop pinfo; - png_set_mem_fn(png_ptr, NULL, NULL, NULL); - pinfo = (memory_infop)png_malloc(png_ptr, - (png_uint_32)png_sizeof(*pinfo)); - pinfo->size = size; - current_allocation += size; - total_allocation += size; - num_allocations ++; - if (current_allocation > maximum_allocation) - maximum_allocation = current_allocation; - pinfo->pointer = (png_voidp)png_malloc(png_ptr, size); - /* Restore malloc_fn and free_fn */ - png_set_mem_fn(png_ptr, - png_voidp_NULL, (png_malloc_ptr)png_debug_malloc, - (png_free_ptr)png_debug_free); - if (size != 0 && pinfo->pointer == NULL) - { - current_allocation -= size; - total_allocation -= size; - png_error(png_ptr, - "out of memory in pngtest->png_debug_malloc."); - } - pinfo->next = pinformation; - pinformation = pinfo; - /* Make sure the caller isn't assuming zeroed memory. */ - png_memset(pinfo->pointer, 0xdd, pinfo->size); - if (verbose) - printf("png_malloc %lu bytes at %x\n", (unsigned long)size, - pinfo->pointer); - return (png_voidp)(pinfo->pointer); - } -} - -/* Free a pointer. It is removed from the list at the same time. */ -void -png_debug_free(png_structp png_ptr, png_voidp ptr) -{ - if (png_ptr == NULL) - fprintf(STDERR, "NULL pointer to png_debug_free.\n"); - if (ptr == 0) - { -#if 0 /* This happens all the time. */ - fprintf(STDERR, "WARNING: freeing NULL pointer\n"); -#endif - return; - } - - /* Unlink the element from the list. */ - { - memory_infop FAR *ppinfo = &pinformation; - for (;;) - { - memory_infop pinfo = *ppinfo; - if (pinfo->pointer == ptr) - { - *ppinfo = pinfo->next; - current_allocation -= pinfo->size; - if (current_allocation < 0) - fprintf(STDERR, "Duplicate free of memory\n"); - /* We must free the list element too, but first kill - the memory that is to be freed. */ - png_memset(ptr, 0x55, pinfo->size); - png_free_default(png_ptr, pinfo); - pinfo = NULL; - break; - } - if (pinfo->next == NULL) - { - fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr); - break; - } - ppinfo = &pinfo->next; - } - } - - /* Finally free the data. */ - if (verbose) - printf("Freeing %x\n", ptr); - png_free_default(png_ptr, ptr); - ptr = NULL; -} -#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */ -/* END of code to test memory allocation/deallocation */ - - -/* Demonstration of user chunk support of the sTER and vpAg chunks */ -#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - -/* (sTER is a public chunk not yet known by libpng. vpAg is a private -chunk used in ImageMagick to store "virtual page" size). */ - -static png_uint_32 user_chunk_data[4]; - - /* 0: sTER mode + 1 - * 1: vpAg width - * 2: vpAg height - * 3: vpAg units - */ - -static int read_user_chunk_callback(png_struct *png_ptr, - png_unknown_chunkp chunk) -{ - png_uint_32 - *my_user_chunk_data; - - /* Return one of the following: - * return (-n); chunk had an error - * return (0); did not recognize - * return (n); success - * - * The unknown chunk structure contains the chunk data: - * png_byte name[5]; - * png_byte *data; - * png_size_t size; - * - * Note that libpng has already taken care of the CRC handling. - */ - - if (chunk->name[0] == 115 && chunk->name[1] == 84 && /* s T */ - chunk->name[2] == 69 && chunk->name[3] == 82) /* E R */ - { - /* Found sTER chunk */ - if (chunk->size != 1) - return (-1); /* Error return */ - if (chunk->data[0] != 0 && chunk->data[0] != 1) - return (-1); /* Invalid mode */ - my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr); - my_user_chunk_data[0]=chunk->data[0]+1; - return (1); - } - - if (chunk->name[0] != 118 || chunk->name[1] != 112 || /* v p */ - chunk->name[2] != 65 || chunk->name[3] != 103) /* A g */ - return (0); /* Did not recognize */ - - /* Found ImageMagick vpAg chunk */ - - if (chunk->size != 9) - return (-1); /* Error return */ - - my_user_chunk_data=(png_uint_32 *) png_get_user_chunk_ptr(png_ptr); - - my_user_chunk_data[1]=png_get_uint_31(png_ptr, chunk->data); - my_user_chunk_data[2]=png_get_uint_31(png_ptr, chunk->data + 4); - my_user_chunk_data[3]=(png_uint_32)chunk->data[8]; - - return (1); - -} -#endif -/* END of code to demonstrate user chunk support */ - -/* Test one file */ -int -test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) -{ - static png_FILE_p fpin; - static png_FILE_p fpout; /* "static" prevents setjmp corruption */ - png_structp read_ptr; - png_infop read_info_ptr, end_info_ptr; -#ifdef PNG_WRITE_SUPPORTED - png_structp write_ptr; - png_infop write_info_ptr; - png_infop write_end_info_ptr; -#else - png_structp write_ptr = NULL; - png_infop write_info_ptr = NULL; - png_infop write_end_info_ptr = NULL; -#endif - png_bytep row_buf; - png_uint_32 y; - png_uint_32 width, height; - int num_pass, pass; - int bit_depth, color_type; -#ifdef PNG_SETJMP_SUPPORTED -#ifdef USE_FAR_KEYWORD - jmp_buf jmpbuf; -#endif -#endif - -#if defined(_WIN32_WCE) - TCHAR path[MAX_PATH]; -#endif - char inbuf[256], outbuf[256]; - - row_buf = NULL; - -#if defined(_WIN32_WCE) - MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH); - if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) -#else - if ((fpin = fopen(inname, "rb")) == NULL) -#endif - { - fprintf(STDERR, "Could not find input file %s\n", inname); - return (1); - } - -#if defined(_WIN32_WCE) - MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH); - if ((fpout = CreateFile(path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL)) == INVALID_HANDLE_VALUE) -#else - if ((fpout = fopen(outname, "wb")) == NULL) -#endif - { - fprintf(STDERR, "Could not open output file %s\n", outname); - FCLOSE(fpin); - return (1); - } - - png_debug(0, "Allocating read and write structures"); -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - read_ptr = - png_create_read_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL, - png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL, - (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); -#else - read_ptr = - png_create_read_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, - png_error_ptr_NULL, png_error_ptr_NULL); -#endif -#if defined(PNG_NO_STDIO) - png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error, - pngtest_warning); -#endif - -#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - user_chunk_data[0] = 0; - user_chunk_data[1] = 0; - user_chunk_data[2] = 0; - user_chunk_data[3] = 0; - png_set_read_user_chunk_fn(read_ptr, user_chunk_data, - read_user_chunk_callback); - -#endif -#ifdef PNG_WRITE_SUPPORTED -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - write_ptr = - png_create_write_struct_2(PNG_LIBPNG_VER_STRING, png_voidp_NULL, - png_error_ptr_NULL, png_error_ptr_NULL, png_voidp_NULL, - (png_malloc_ptr)png_debug_malloc, (png_free_ptr)png_debug_free); -#else - write_ptr = - png_create_write_struct(PNG_LIBPNG_VER_STRING, png_voidp_NULL, - png_error_ptr_NULL, png_error_ptr_NULL); -#endif -#if defined(PNG_NO_STDIO) - png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error, - pngtest_warning); -#endif -#endif - png_debug(0, "Allocating read_info, write_info and end_info structures"); - read_info_ptr = png_create_info_struct(read_ptr); - end_info_ptr = png_create_info_struct(read_ptr); -#ifdef PNG_WRITE_SUPPORTED - write_info_ptr = png_create_info_struct(write_ptr); - write_end_info_ptr = png_create_info_struct(write_ptr); -#endif - -#ifdef PNG_SETJMP_SUPPORTED - png_debug(0, "Setting jmpbuf for read struct"); -#ifdef USE_FAR_KEYWORD - if (setjmp(jmpbuf)) -#else - if (setjmp(png_jmpbuf(read_ptr))) -#endif - { - fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); - png_free(read_ptr, row_buf); - row_buf = NULL; - png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); -#ifdef PNG_WRITE_SUPPORTED - png_destroy_info_struct(write_ptr, &write_end_info_ptr); - png_destroy_write_struct(&write_ptr, &write_info_ptr); -#endif - FCLOSE(fpin); - FCLOSE(fpout); - return (1); - } -#ifdef USE_FAR_KEYWORD - png_memcpy(png_jmpbuf(read_ptr), jmpbuf, png_sizeof(jmp_buf)); -#endif - -#ifdef PNG_WRITE_SUPPORTED - png_debug(0, "Setting jmpbuf for write struct"); -#ifdef USE_FAR_KEYWORD - if (setjmp(jmpbuf)) -#else - if (setjmp(png_jmpbuf(write_ptr))) -#endif - { - fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname); - png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); - png_destroy_info_struct(write_ptr, &write_end_info_ptr); -#ifdef PNG_WRITE_SUPPORTED - png_destroy_write_struct(&write_ptr, &write_info_ptr); -#endif - FCLOSE(fpin); - FCLOSE(fpout); - return (1); - } -#ifdef USE_FAR_KEYWORD - png_memcpy(png_jmpbuf(write_ptr), jmpbuf, png_sizeof(jmp_buf)); -#endif -#endif -#endif - - png_debug(0, "Initializing input and output streams"); -#if !defined(PNG_NO_STDIO) - png_init_io(read_ptr, fpin); -# ifdef PNG_WRITE_SUPPORTED - png_init_io(write_ptr, fpout); -# endif -#else - png_set_read_fn(read_ptr, (png_voidp)fpin, pngtest_read_data); -# ifdef PNG_WRITE_SUPPORTED - png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data, -# if defined(PNG_WRITE_FLUSH_SUPPORTED) - pngtest_flush); -# else - NULL); -# endif -# endif -#endif - if (status_dots_requested == 1) - { -#ifdef PNG_WRITE_SUPPORTED - png_set_write_status_fn(write_ptr, write_row_callback); -#endif - png_set_read_status_fn(read_ptr, read_row_callback); - } - else - { -#ifdef PNG_WRITE_SUPPORTED - png_set_write_status_fn(write_ptr, png_write_status_ptr_NULL); -#endif - png_set_read_status_fn(read_ptr, png_read_status_ptr_NULL); - } - -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) - { - int i; - for (i = 0; i<256; i++) - filters_used[i] = 0; - png_set_read_user_transform_fn(read_ptr, count_filters); - } -#endif -#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) - zero_samples = 0; - png_set_write_user_transform_fn(write_ptr, count_zero_samples); -#endif - -#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) -# ifndef PNG_HANDLE_CHUNK_ALWAYS -# define PNG_HANDLE_CHUNK_ALWAYS 3 -# endif - png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, - png_bytep_NULL, 0); -#endif -#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) -# ifndef PNG_HANDLE_CHUNK_IF_SAFE -# define PNG_HANDLE_CHUNK_IF_SAFE 2 -# endif - png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_IF_SAFE, - png_bytep_NULL, 0); -#endif - - png_debug(0, "Reading info struct"); - png_read_info(read_ptr, read_info_ptr); - - png_debug(0, "Transferring info struct"); - { - int interlace_type, compression_type, filter_type; - - if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, - &color_type, &interlace_type, &compression_type, &filter_type)) - { - png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, -#if defined(PNG_WRITE_INTERLACING_SUPPORTED) - color_type, interlace_type, compression_type, filter_type); -#else - color_type, PNG_INTERLACE_NONE, compression_type, filter_type); -#endif - } - } -#if defined(PNG_FIXED_POINT_SUPPORTED) -#if defined(PNG_cHRM_SUPPORTED) - { - png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x, - blue_y; - if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, - &red_y, &green_x, &green_y, &blue_x, &blue_y)) - { - png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x, - red_y, green_x, green_y, blue_x, blue_y); - } - } -#endif -#if defined(PNG_gAMA_SUPPORTED) - { - png_fixed_point gamma; - - if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma)) - png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma); - } -#endif -#else /* Use floating point versions */ -#if defined(PNG_FLOATING_POINT_SUPPORTED) -#if defined(PNG_cHRM_SUPPORTED) - { - double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, - blue_y; - if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, - &red_y, &green_x, &green_y, &blue_x, &blue_y)) - { - png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x, - red_y, green_x, green_y, blue_x, blue_y); - } - } -#endif -#if defined(PNG_gAMA_SUPPORTED) - { - double gamma; - - if (png_get_gAMA(read_ptr, read_info_ptr, &gamma)) - png_set_gAMA(write_ptr, write_info_ptr, gamma); - } -#endif -#endif /* Floating point */ -#endif /* Fixed point */ -#if defined(PNG_iCCP_SUPPORTED) - { - png_charp name; - png_charp profile; - png_uint_32 proflen; - int compression_type; - - if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type, - &profile, &proflen)) - { - png_set_iCCP(write_ptr, write_info_ptr, name, compression_type, - profile, proflen); - } - } -#endif -#if defined(PNG_sRGB_SUPPORTED) - { - int intent; - - if (png_get_sRGB(read_ptr, read_info_ptr, &intent)) - png_set_sRGB(write_ptr, write_info_ptr, intent); - } -#endif - { - png_colorp palette; - int num_palette; - - if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette)) - png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); - } -#if defined(PNG_bKGD_SUPPORTED) - { - png_color_16p background; - - if (png_get_bKGD(read_ptr, read_info_ptr, &background)) - { - png_set_bKGD(write_ptr, write_info_ptr, background); - } - } -#endif -#if defined(PNG_hIST_SUPPORTED) - { - png_uint_16p hist; - - if (png_get_hIST(read_ptr, read_info_ptr, &hist)) - png_set_hIST(write_ptr, write_info_ptr, hist); - } -#endif -#if defined(PNG_oFFs_SUPPORTED) - { - png_int_32 offset_x, offset_y; - int unit_type; - - if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y, - &unit_type)) - { - png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type); - } - } -#endif -#if defined(PNG_pCAL_SUPPORTED) - { - png_charp purpose, units; - png_charpp params; - png_int_32 X0, X1; - int type, nparams; - - if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type, - &nparams, &units, ¶ms)) - { - png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type, - nparams, units, params); - } - } -#endif -#if defined(PNG_pHYs_SUPPORTED) - { - png_uint_32 res_x, res_y; - int unit_type; - - if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type)) - png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type); - } -#endif -#if defined(PNG_sBIT_SUPPORTED) - { - png_color_8p sig_bit; - - if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit)) - png_set_sBIT(write_ptr, write_info_ptr, sig_bit); - } -#endif -#if defined(PNG_sCAL_SUPPORTED) -#ifdef PNG_FLOATING_POINT_SUPPORTED - { - int unit; - double scal_width, scal_height; - - if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width, - &scal_height)) - { - png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height); - } - } -#else -#ifdef PNG_FIXED_POINT_SUPPORTED - { - int unit; - png_charp scal_width, scal_height; - - if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width, - &scal_height)) - { - png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, scal_height); - } - } -#endif -#endif -#endif -#if defined(PNG_TEXT_SUPPORTED) - { - png_textp text_ptr; - int num_text; - - if (png_get_text(read_ptr, read_info_ptr, &text_ptr, &num_text) > 0) - { - png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks", num_text); - png_set_text(write_ptr, write_info_ptr, text_ptr, num_text); - } - } -#endif -#if defined(PNG_tIME_SUPPORTED) - { - png_timep mod_time; - - if (png_get_tIME(read_ptr, read_info_ptr, &mod_time)) - { - png_set_tIME(write_ptr, write_info_ptr, mod_time); -#if defined(PNG_TIME_RFC1123_SUPPORTED) - /* We have to use png_memcpy instead of "=" because the string - * pointed to by png_convert_to_rfc1123() gets free'ed before - * we use it. - */ - png_memcpy(tIME_string, - png_convert_to_rfc1123(read_ptr, mod_time), - png_sizeof(tIME_string)); - tIME_string[png_sizeof(tIME_string) - 1] = '\0'; - tIME_chunk_present++; -#endif /* PNG_TIME_RFC1123_SUPPORTED */ - } - } -#endif -#if defined(PNG_tRNS_SUPPORTED) - { - png_bytep trans; - int num_trans; - png_color_16p trans_values; - - if (png_get_tRNS(read_ptr, read_info_ptr, &trans, &num_trans, - &trans_values)) - { - int sample_max = (1 << read_info_ptr->bit_depth); - /* libpng doesn't reject a tRNS chunk with out-of-range samples */ - if (!((read_info_ptr->color_type == PNG_COLOR_TYPE_GRAY && - (int)trans_values->gray > sample_max) || - (read_info_ptr->color_type == PNG_COLOR_TYPE_RGB && - ((int)trans_values->red > sample_max || - (int)trans_values->green > sample_max || - (int)trans_values->blue > sample_max)))) - png_set_tRNS(write_ptr, write_info_ptr, trans, num_trans, - trans_values); - } - } -#endif -#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) - { - png_unknown_chunkp unknowns; - int num_unknowns = (int)png_get_unknown_chunks(read_ptr, read_info_ptr, - &unknowns); - if (num_unknowns) - { - png_size_t i; - png_set_unknown_chunks(write_ptr, write_info_ptr, unknowns, - num_unknowns); - /* Copy the locations from the read_info_ptr. The automatically - * generated locations in write_info_ptr are wrong because we - * haven't written anything yet. - */ - for (i = 0; i < (png_size_t)num_unknowns; i++) - png_set_unknown_chunk_location(write_ptr, write_info_ptr, i, - unknowns[i].location); - } - } -#endif - -#ifdef PNG_WRITE_SUPPORTED - png_debug(0, "Writing info struct"); - -/* If we wanted, we could write info in two steps: - * png_write_info_before_PLTE(write_ptr, write_info_ptr); - */ - png_write_info(write_ptr, write_info_ptr); - -#if defined(PNG_UNKNOWN_CHUNKS_SUPPORTED) - if (user_chunk_data[0] != 0) - { - png_byte png_sTER[5] = {115, 84, 69, 82, '\0'}; - - unsigned char - ster_chunk_data[1]; - - if (verbose) - fprintf(STDERR, "\n stereo mode = %lu\n", - (unsigned long)(user_chunk_data[0] - 1)); - ster_chunk_data[0]=(unsigned char)(user_chunk_data[0] - 1); - png_write_chunk(write_ptr, png_sTER, ster_chunk_data, 1); - } - if (user_chunk_data[1] != 0 || user_chunk_data[2] != 0) - { - png_byte png_vpAg[5] = {118, 112, 65, 103, '\0'}; - - unsigned char - vpag_chunk_data[9]; - - if (verbose) - fprintf(STDERR, " vpAg = %lu x %lu, units = %lu\n", - (unsigned long)user_chunk_data[1], - (unsigned long)user_chunk_data[2], - (unsigned long)user_chunk_data[3]); - png_save_uint_32(vpag_chunk_data, user_chunk_data[1]); - png_save_uint_32(vpag_chunk_data + 4, user_chunk_data[2]); - vpag_chunk_data[8] = (unsigned char)(user_chunk_data[3] & 0xff); - png_write_chunk(write_ptr, png_vpAg, vpag_chunk_data, 9); - } - -#endif -#endif - -#ifdef SINGLE_ROWBUF_ALLOC - png_debug(0, "Allocating row buffer..."); - row_buf = (png_bytep)png_malloc(read_ptr, - png_get_rowbytes(read_ptr, read_info_ptr)); - png_debug1(0, "0x%08lx", (unsigned long)row_buf); -#endif /* SINGLE_ROWBUF_ALLOC */ - png_debug(0, "Writing row data"); - -#if defined(PNG_READ_INTERLACING_SUPPORTED) || \ - defined(PNG_WRITE_INTERLACING_SUPPORTED) - num_pass = png_set_interlace_handling(read_ptr); -# ifdef PNG_WRITE_SUPPORTED - png_set_interlace_handling(write_ptr); -# endif -#else - num_pass = 1; -#endif - -#ifdef PNGTEST_TIMING - t_stop = (float)clock(); - t_misc += (t_stop - t_start); - t_start = t_stop; -#endif - for (pass = 0; pass < num_pass; pass++) - { - png_debug1(0, "Writing row data for pass %d", pass); - for (y = 0; y < height; y++) - { -#ifndef SINGLE_ROWBUF_ALLOC - png_debug2(0, "Allocating row buffer (pass %d, y = %ld)...", pass, y); - row_buf = (png_bytep)png_malloc(read_ptr, - png_get_rowbytes(read_ptr, read_info_ptr)); - png_debug2(0, "0x%08lx (%ld bytes)", (unsigned long)row_buf, - png_get_rowbytes(read_ptr, read_info_ptr)); -#endif /* !SINGLE_ROWBUF_ALLOC */ - png_read_rows(read_ptr, (png_bytepp)&row_buf, png_bytepp_NULL, 1); - -#ifdef PNG_WRITE_SUPPORTED -#ifdef PNGTEST_TIMING - t_stop = (float)clock(); - t_decode += (t_stop - t_start); - t_start = t_stop; -#endif - png_write_rows(write_ptr, (png_bytepp)&row_buf, 1); -#ifdef PNGTEST_TIMING - t_stop = (float)clock(); - t_encode += (t_stop - t_start); - t_start = t_stop; -#endif -#endif /* PNG_WRITE_SUPPORTED */ - -#ifndef SINGLE_ROWBUF_ALLOC - png_debug2(0, "Freeing row buffer (pass %d, y = %ld)", pass, y); - png_free(read_ptr, row_buf); - row_buf = NULL; -#endif /* !SINGLE_ROWBUF_ALLOC */ - } - } - -#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) - png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1); -#endif -#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) - png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1); -#endif - - png_debug(0, "Reading and writing end_info data"); - - png_read_end(read_ptr, end_info_ptr); -#if defined(PNG_TEXT_SUPPORTED) - { - png_textp text_ptr; - int num_text; - - if (png_get_text(read_ptr, end_info_ptr, &text_ptr, &num_text) > 0) - { - png_debug1(0, "Handling %d iTXt/tEXt/zTXt chunks", num_text); - png_set_text(write_ptr, write_end_info_ptr, text_ptr, num_text); - } - } -#endif -#if defined(PNG_tIME_SUPPORTED) - { - png_timep mod_time; - - if (png_get_tIME(read_ptr, end_info_ptr, &mod_time)) - { - png_set_tIME(write_ptr, write_end_info_ptr, mod_time); -#if defined(PNG_TIME_RFC1123_SUPPORTED) - /* We have to use png_memcpy instead of "=" because the string - pointed to by png_convert_to_rfc1123() gets free'ed before - we use it */ - png_memcpy(tIME_string, - png_convert_to_rfc1123(read_ptr, mod_time), - png_sizeof(tIME_string)); - tIME_string[png_sizeof(tIME_string) - 1] = '\0'; - tIME_chunk_present++; -#endif /* PNG_TIME_RFC1123_SUPPORTED */ - } - } -#endif -#if defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) - { - png_unknown_chunkp unknowns; - int num_unknowns; - num_unknowns = (int)png_get_unknown_chunks(read_ptr, end_info_ptr, - &unknowns); - if (num_unknowns) - { - png_size_t i; - png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns, - num_unknowns); - /* Copy the locations from the read_info_ptr. The automatically - * generated locations in write_end_info_ptr are wrong because we - * haven't written the end_info yet. - */ - for (i = 0; i < (png_size_t)num_unknowns; i++) - png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i, - unknowns[i].location); - } - } -#endif -#ifdef PNG_WRITE_SUPPORTED - png_write_end(write_ptr, write_end_info_ptr); -#endif - -#ifdef PNG_EASY_ACCESS_SUPPORTED - if (verbose) - { - png_uint_32 iwidth, iheight; - iwidth = png_get_image_width(write_ptr, write_info_ptr); - iheight = png_get_image_height(write_ptr, write_info_ptr); - fprintf(STDERR, "\n Image width = %lu, height = %lu\n", - (unsigned long)iwidth, (unsigned long)iheight); - } -#endif - - png_debug(0, "Destroying data structs"); -#ifdef SINGLE_ROWBUF_ALLOC - png_debug(1, "destroying row_buf for read_ptr"); - png_free(read_ptr, row_buf); - row_buf = NULL; -#endif /* SINGLE_ROWBUF_ALLOC */ - png_debug(1, "destroying read_ptr, read_info_ptr, end_info_ptr"); - png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); -#ifdef PNG_WRITE_SUPPORTED - png_debug(1, "destroying write_end_info_ptr"); - png_destroy_info_struct(write_ptr, &write_end_info_ptr); - png_debug(1, "destroying write_ptr, write_info_ptr"); - png_destroy_write_struct(&write_ptr, &write_info_ptr); -#endif - png_debug(0, "Destruction complete."); - - FCLOSE(fpin); - FCLOSE(fpout); - - png_debug(0, "Opening files for comparison"); -#if defined(_WIN32_WCE) - MultiByteToWideChar(CP_ACP, 0, inname, -1, path, MAX_PATH); - if ((fpin = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) -#else - if ((fpin = fopen(inname, "rb")) == NULL) -#endif - { - fprintf(STDERR, "Could not find file %s\n", inname); - return (1); - } - -#if defined(_WIN32_WCE) - MultiByteToWideChar(CP_ACP, 0, outname, -1, path, MAX_PATH); - if ((fpout = CreateFile(path, GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL)) == INVALID_HANDLE_VALUE) -#else - if ((fpout = fopen(outname, "rb")) == NULL) -#endif - { - fprintf(STDERR, "Could not find file %s\n", outname); - FCLOSE(fpin); - return (1); - } - - for (;;) - { - png_size_t num_in, num_out; - - READFILE(fpin, inbuf, 1, num_in); - READFILE(fpout, outbuf, 1, num_out); - - if (num_in != num_out) - { - fprintf(STDERR, "\nFiles %s and %s are of a different size\n", - inname, outname); - if (wrote_question == 0) - { - fprintf(STDERR, - " Was %s written with the same maximum IDAT chunk size (%d bytes),", - inname, PNG_ZBUF_SIZE); - fprintf(STDERR, - "\n filtering heuristic (libpng default), compression"); - fprintf(STDERR, - " level (zlib default),\n and zlib version (%s)?\n\n", - ZLIB_VERSION); - wrote_question = 1; - } - FCLOSE(fpin); - FCLOSE(fpout); - return (0); - } - - if (!num_in) - break; - - if (png_memcmp(inbuf, outbuf, num_in)) - { - fprintf(STDERR, "\nFiles %s and %s are different\n", inname, outname); - if (wrote_question == 0) - { - fprintf(STDERR, - " Was %s written with the same maximum IDAT chunk size (%d bytes),", - inname, PNG_ZBUF_SIZE); - fprintf(STDERR, - "\n filtering heuristic (libpng default), compression"); - fprintf(STDERR, - " level (zlib default),\n and zlib version (%s)?\n\n", - ZLIB_VERSION); - wrote_question = 1; - } - FCLOSE(fpin); - FCLOSE(fpout); - return (0); - } - } - - FCLOSE(fpin); - FCLOSE(fpout); - - return (0); -} - -/* Input and output filenames */ -#ifdef RISCOS -static PNG_CONST char *inname = "pngtest/png"; -static PNG_CONST char *outname = "pngout/png"; -#else -static PNG_CONST char *inname = "pngtest.png"; -static PNG_CONST char *outname = "pngout.png"; -#endif - -int -main(int argc, char *argv[]) -{ - int multiple = 0; - int ierror = 0; - - fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING); - fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION); - fprintf(STDERR, "%s", png_get_copyright(NULL)); - /* Show the version of libpng used in building the library */ - fprintf(STDERR, " library (%lu):%s", - (unsigned long)png_access_version_number(), - png_get_header_version(NULL)); - /* Show the version of libpng used in building the application */ - fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER, - PNG_HEADER_VERSION_STRING); - fprintf(STDERR, " sizeof(png_struct)=%ld, sizeof(png_info)=%ld\n", - (long)png_sizeof(png_struct), (long)png_sizeof(png_info)); - - /* Do some consistency checking on the memory allocation settings, I'm - * not sure this matters, but it is nice to know, the first of these - * tests should be impossible because of the way the macros are set - * in pngconf.h - */ -#if defined(MAXSEG_64K) && !defined(PNG_MAX_MALLOC_64K) - fprintf(STDERR, " NOTE: Zlib compiled for max 64k, libpng not\n"); -#endif - /* I think the following can happen. */ -#if !defined(MAXSEG_64K) && defined(PNG_MAX_MALLOC_64K) - fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n"); -#endif - - if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING)) - { - fprintf(STDERR, - "Warning: versions are different between png.h and png.c\n"); - fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING); - fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver); - ++ierror; - } - - if (argc > 1) - { - if (strcmp(argv[1], "-m") == 0) - { - multiple = 1; - status_dots_requested = 0; - } - else if (strcmp(argv[1], "-mv") == 0 || - strcmp(argv[1], "-vm") == 0 ) - { - multiple = 1; - verbose = 1; - status_dots_requested = 1; - } - else if (strcmp(argv[1], "-v") == 0) - { - verbose = 1; - status_dots_requested = 1; - inname = argv[2]; - } - else - { - inname = argv[1]; - status_dots_requested = 0; - } - } - - if (!multiple && argc == 3 + verbose) - outname = argv[2 + verbose]; - - if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2)) - { - fprintf(STDERR, - "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n", - argv[0], argv[0]); - fprintf(STDERR, - " reads/writes one PNG file (without -m) or multiple files (-m)\n"); - fprintf(STDERR, - " with -m %s is used as a temporary file\n", outname); - exit(1); - } - - if (multiple) - { - int i; -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - int allocation_now = current_allocation; -#endif - for (i=2; isize, - (unsigned int) pinfo->pointer); - pinfo = pinfo->next; - } - } -#endif - } -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - fprintf(STDERR, " Current memory allocation: %10d bytes\n", - current_allocation); - fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", - maximum_allocation); - fprintf(STDERR, " Total memory allocation: %10d bytes\n", - total_allocation); - fprintf(STDERR, " Number of allocations: %10d\n", - num_allocations); -#endif - } - else - { - int i; - for (i = 0; i<3; ++i) - { - int kerror; -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - int allocation_now = current_allocation; -#endif - if (i == 1) status_dots_requested = 1; - else if (verbose == 0)status_dots_requested = 0; - if (i == 0 || verbose == 1 || ierror != 0) - fprintf(STDERR, "\n Testing %s:", inname); - kerror = test_one_file(inname, outname); - if (kerror == 0) - { - if (verbose == 1 || i == 2) - { -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) - int k; -#endif -#if defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) - fprintf(STDERR, "\n PASS (%lu zero samples)\n", - (unsigned long)zero_samples); -#else - fprintf(STDERR, " PASS\n"); -#endif -#if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) - for (k = 0; k<256; k++) - if (filters_used[k]) - fprintf(STDERR, " Filter %d was used %lu times\n", - k, - (unsigned long)filters_used[k]); -#endif -#if defined(PNG_TIME_RFC1123_SUPPORTED) - if (tIME_chunk_present != 0) - fprintf(STDERR, " tIME = %s\n", tIME_string); -#endif /* PNG_TIME_RFC1123_SUPPORTED */ - } - } - else - { - if (verbose == 0 && i != 2) - fprintf(STDERR, "\n Testing %s:", inname); - fprintf(STDERR, " FAIL\n"); - ierror += kerror; - } -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - if (allocation_now != current_allocation) - fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n", - current_allocation - allocation_now); - if (current_allocation != 0) - { - memory_infop pinfo = pinformation; - - fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", - current_allocation); - while (pinfo != NULL) - { - fprintf(STDERR, " %lu bytes at %x\n", - (unsigned long)pinfo->size, (unsigned int)pinfo->pointer); - pinfo = pinfo->next; - } - } -#endif - } -#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG - fprintf(STDERR, " Current memory allocation: %10d bytes\n", - current_allocation); - fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", - maximum_allocation); - fprintf(STDERR, " Total memory allocation: %10d bytes\n", - total_allocation); - fprintf(STDERR, " Number of allocations: %10d\n", - num_allocations); -#endif - } - -#ifdef PNGTEST_TIMING - t_stop = (float)clock(); - t_misc += (t_stop - t_start); - t_start = t_stop; - fprintf(STDERR, " CPU time used = %.3f seconds", - (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC); - fprintf(STDERR, " (decoding %.3f,\n", - t_decode/(float)CLOCKS_PER_SEC); - fprintf(STDERR, " encoding %.3f ,", - t_encode/(float)CLOCKS_PER_SEC); - fprintf(STDERR, " other %.3f seconds)\n\n", - t_misc/(float)CLOCKS_PER_SEC); -#endif - - if (ierror == 0) - fprintf(STDERR, " libpng passes test\n"); - else - fprintf(STDERR, " libpng FAILS test\n"); - return (int)(ierror != 0); -} - -/* Generate a compiler error if there is an old png.h in the search path. */ -typedef version_1_2_37rc01 your_png_h_is_not_version_1_2_37rc01; diff --git a/pngwio.c b/pngwio.c index c62ea995b..740b71d71 100644 --- a/pngwio.c +++ b/pngwio.c @@ -1,7 +1,7 @@ /* pngwio.c - functions for data output * - * Last changed in libpng 1.2.37 [May 27, 2009] + * Last changed in libpng 1.2.37 [June 4, 2009] * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) @@ -47,7 +47,8 @@ png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { png_uint_32 check; - if (png_ptr == NULL) return; + if (png_ptr == NULL) + return; #if defined(_WIN32_WCE) if ( !WriteFile((HANDLE)(png_ptr->io_ptr), data, length, &check, NULL) ) check = 0; @@ -73,7 +74,8 @@ png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) png_byte *near_data; /* Needs to be "png_byte *" instead of "png_bytep" */ png_FILE_p io_ptr; - if (png_ptr == NULL) return; + if (png_ptr == NULL) + return; /* Check if data really is near. If so, use usual code. */ near_data = (png_byte *)CVT_PTR_NOCHECK(data); io_ptr = (png_FILE_p)CVT_PTR(png_ptr->io_ptr); diff --git a/pngwrite.c b/pngwrite.c index f74d08105..bd6263c21 100644 --- a/pngwrite.c +++ b/pngwrite.c @@ -1,7 +1,7 @@ /* pngwrite.c - general routines to write a PNG file * - * Last changed in libpng 1.2.37 [May 27, 2009] + * Last changed in libpng 1.2.37 [June 4, 2009] * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) diff --git a/pngwtran.c b/pngwtran.c index 7bf1b0318..ac563390c 100644 --- a/pngwtran.c +++ b/pngwtran.c @@ -1,7 +1,7 @@ /* pngwtran.c - transforms the data in a row for PNG writers * - * Last changed in libpng 1.2.37 [May 27, 2009] + * Last changed in libpng 1.2.37 [June 4, 2009] * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) diff --git a/pngwutil.c b/pngwutil.c index de6a069df..22a83ccb0 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -1,7 +1,7 @@ /* pngwutil.c - utilities to write a PNG file * - * Last changed in libpng 1.2.36 [May 27, 2009] + * Last changed in libpng 1.2.36 [June 4, 2009] * For conditions of distribution and use, see copyright notice in png.h * Copyright (c) 1998-2009 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)