diff --git a/ChangeLog.txt b/ChangeLog.txt new file mode 100644 index 000000000..4d94cb9a3 --- /dev/null +++ b/ChangeLog.txt @@ -0,0 +1,6344 @@ + +Change log: + +Version 1.6.17 (built with libpng-1.2.36and 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" + +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 #ifdef'ed out + 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 CRC's 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 libpng's 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. + + #ifdef'ed 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 + + #ifdef'ed 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. + + #ifdef'ed 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 wasn't 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_save b/ChangeLog.txt_save new file mode 100644 index 000000000..8385a959d --- /dev/null +++ b/ChangeLog.txt_save @@ -0,0 +1,420 @@ +Change log: + +Version 1.6.17 (built with libpng-1.2.36rc01 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" + +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 #ifdef'ed out + 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 CRC's 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 libpng's 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. + + #ifdef'ed 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 + + #ifdef'ed 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. + + #ifdef'ed 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 wasn't 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/example.c b/example.c deleted file mode 100644 index 83dd05bd7..000000000 --- a/example.c +++ /dev/null @@ -1,814 +0,0 @@ - -#if 0 /* in case someone actually tries to compile this */ - -/* example.c - an example of using libpng - * Last changed in libpng 1.2.35 [February 14, 2009] - * This file has been placed in the public domain by the authors. - * Maintained 1998-2009 Glenn Randers-Pehrson - * Maintained 1996, 1997 Andreas Dilger) - * Written 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - */ - -/* This is an example of how to use libpng to read and write PNG files. - * The file libpng.txt is much more verbose then this. If you have not - * read it, do so first. This was designed to be a starting point of an - * implementation. This is not officially part of libpng, is hereby placed - * in the public domain, and therefore does not require a copyright notice. - * - * This file does not currently compile, because it is missing certain - * parts, like allocating memory to hold an image. You will have to - * supply these parts to get it to compile. For an example of a minimal - * working PNG reader/writer, see pngtest.c, included in this distribution; - * see also the programs in the contrib directory. - */ - -#include "png.h" - - /* The png_jmpbuf() macro, used in error handling, became available in - * libpng version 1.0.6. If you want to be able to run your code with older - * versions of libpng, you must define the macro yourself (but only if it - * is not already defined by libpng!). - */ - -#ifndef png_jmpbuf -# define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf) -#endif - -/* Check to see if a file is a PNG file using png_sig_cmp(). png_sig_cmp() - * returns zero if the image is a PNG and nonzero if it isn't a PNG. - * - * The function check_if_png() shown here, but not used, returns nonzero (true) - * if the file can be opened and is a PNG, 0 (false) otherwise. - * - * If this call is successful, and you are going to keep the file open, - * you should call png_set_sig_bytes(png_ptr, PNG_BYTES_TO_CHECK); once - * you have created the png_ptr, so that libpng knows your application - * has read that many bytes from the start of the file. Make sure you - * don't call png_set_sig_bytes() with more than 8 bytes read or give it - * an incorrect number of bytes read, or you will either have read too - * many bytes (your fault), or you are telling libpng to read the wrong - * number of magic bytes (also your fault). - * - * Many applications already read the first 2 or 4 bytes from the start - * of the image to determine the file type, so it would be easiest just - * to pass the bytes to png_sig_cmp() or even skip that if you know - * you have a PNG file, and call png_set_sig_bytes(). - */ -#define PNG_BYTES_TO_CHECK 4 -int check_if_png(char *file_name, FILE **fp) -{ - char buf[PNG_BYTES_TO_CHECK]; - - /* Open the prospective PNG file. */ - if ((*fp = fopen(file_name, "rb")) == NULL) - return 0; - - /* Read in some of the signature bytes */ - if (fread(buf, 1, PNG_BYTES_TO_CHECK, *fp) != PNG_BYTES_TO_CHECK) - return 0; - - /* Compare the first PNG_BYTES_TO_CHECK bytes of the signature. - Return nonzero (true) if they match */ - - return(!png_sig_cmp(buf, (png_size_t)0, PNG_BYTES_TO_CHECK)); -} - -/* Read a PNG file. You may want to return an error code if the read - * fails (depending upon the failure). There are two "prototypes" given - * here - one where we are given the filename, and we need to open the - * file, and the other where we are given an open file (possibly with - * some or all of the magic bytes read - see comments above). - */ -#ifdef open_file /* prototype 1 */ -void read_png(char *file_name) /* We need to open the file */ -{ - png_structp png_ptr; - png_infop info_ptr; - unsigned int sig_read = 0; - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; - FILE *fp; - - if ((fp = fopen(file_name, "rb")) == NULL) - return (ERROR); -#else no_open_file /* prototype 2 */ -void read_png(FILE *fp, unsigned int sig_read) /* file is already open */ -{ - png_structp png_ptr; - png_infop info_ptr; - png_uint_32 width, height; - int bit_depth, color_type, interlace_type; -#endif no_open_file /* only use one prototype! */ - - /* Create and initialize the png_struct with the desired error handler - * functions. If you want to use the default stderr and longjump method, - * you can supply NULL for the last three parameters. We also supply the - * the compiler header file version, so that we know if the application - * was compiled with a compatible version of the library. REQUIRED - */ - png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, - png_voidp user_error_ptr, user_error_fn, user_warning_fn); - - if (png_ptr == NULL) - { - fclose(fp); - return (ERROR); - } - - /* Allocate/initialize the memory for image information. REQUIRED. */ - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) - { - fclose(fp); - png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL); - return (ERROR); - } - - /* Set error handling if you are using the setjmp/longjmp method (this is - * the normal method of doing things with libpng). REQUIRED unless you - * set up your own error handlers in the png_create_read_struct() earlier. - */ - - if (setjmp(png_jmpbuf(png_ptr))) - { - /* Free all of the memory associated with the png_ptr and info_ptr */ - png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); - fclose(fp); - /* If we get here, we had a problem reading the file */ - return (ERROR); - } - - /* One of the following I/O initialization methods is REQUIRED */ -#ifdef streams /* PNG file I/O method 1 */ - /* Set up the input control if you are using standard C streams */ - png_init_io(png_ptr, fp); - -#else no_streams /* PNG file I/O method 2 */ - /* If you are using replacement read functions, instead of calling - * png_init_io() here you would call: - */ - png_set_read_fn(png_ptr, (void *)user_io_ptr, user_read_fn); - /* where user_io_ptr is a structure you want available to the callbacks */ -#endif no_streams /* Use only one I/O method! */ - - /* If we have already read some of the signature */ - png_set_sig_bytes(png_ptr, sig_read); - -#ifdef hilevel - /* - * If you have enough memory to read in the entire image at once, - * and you need to specify only transforms that can be controlled - * with one of the PNG_TRANSFORM_* bits (this presently excludes - * dithering, filling, setting background, and doing gamma - * adjustment), then you can read the entire image (including - * pixels) into the info structure with this call: - */ - png_read_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL); -#else - /* OK, you're doing it the hard way, with the lower-level functions */ - - /* The call to png_read_info() gives us all of the information from the - * PNG file before the first IDAT (image data chunk). REQUIRED - */ - png_read_info(png_ptr, info_ptr); - - png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, - &interlace_type, int_p_NULL, int_p_NULL); - -/* Set up the data transformations you want. Note that these are all - * optional. Only call them if you want/need them. Many of the - * transformations only work on specific types of images, and many - * are mutually exclusive. - */ - - /* tell libpng to strip 16 bit/color files down to 8 bits/color */ - png_set_strip_16(png_ptr); - - /* Strip alpha bytes from the input data without combining with the - * background (not recommended). - */ - png_set_strip_alpha(png_ptr); - - /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single - * byte into separate bytes (useful for paletted and grayscale images). - */ - png_set_packing(png_ptr); - - /* Change the order of packed pixels to least significant bit first - * (not useful if you are using png_set_packing). */ - png_set_packswap(png_ptr); - - /* Expand paletted colors into true RGB triplets */ - if (color_type == PNG_COLOR_TYPE_PALETTE) - png_set_palette_to_rgb(png_ptr); - - /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */ - if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) - png_set_expand_gray_1_2_4_to_8(png_ptr); - - /* Expand paletted or RGB images with transparency to full alpha channels - * so the data will be available as RGBA quartets. - */ - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) - png_set_tRNS_to_alpha(png_ptr); - - /* Set the background color to draw transparent and alpha images over. - * It is possible to set the red, green, and blue components directly - * for paletted images instead of supplying a palette index. Note that - * even if the PNG file supplies a background, you are not required to - * use it - you should use the (solid) application background if it has one. - */ - - png_color_16 my_background, *image_background; - - if (png_get_bKGD(png_ptr, info_ptr, &image_background)) - png_set_background(png_ptr, image_background, - PNG_BACKGROUND_GAMMA_FILE, 1, 1.0); - else - png_set_background(png_ptr, &my_background, - PNG_BACKGROUND_GAMMA_SCREEN, 0, 1.0); - - /* Some suggestions as to how to get a screen gamma value */ - - /* Note that screen gamma is the display_exponent, which includes - * the CRT_exponent and any correction for viewing conditions */ - if (/* We have a user-defined screen gamma value */) - { - screen_gamma = user-defined screen_gamma; - } - /* This is one way that applications share the same screen gamma value */ - else if ((gamma_str = getenv("SCREEN_GAMMA")) != NULL) - { - screen_gamma = atof(gamma_str); - } - /* If we don't have another value */ - else - { - screen_gamma = 2.2; /* A good guess for a PC monitors in a dimly - lit room */ - screen_gamma = 1.7 or 1.0; /* A good guess for Mac systems */ - } - - /* Tell libpng to handle the gamma conversion for you. The final call - * is a good guess for PC generated images, but it should be configurable - * by the user at run time by the user. It is strongly suggested that - * your application support gamma correction. - */ - - int intent; - - if (png_get_sRGB(png_ptr, info_ptr, &intent)) - png_set_gamma(png_ptr, screen_gamma, 0.45455); - else - { - double image_gamma; - if (png_get_gAMA(png_ptr, info_ptr, &image_gamma)) - png_set_gamma(png_ptr, screen_gamma, image_gamma); - else - png_set_gamma(png_ptr, screen_gamma, 0.45455); - } - - /* Dither RGB files down to 8 bit palette or reduce palettes - * to the number of colors available on your screen. - */ - if (color_type & PNG_COLOR_MASK_COLOR) - { - int num_palette; - png_colorp palette; - - /* This reduces the image to the application supplied palette */ - if (/* we have our own palette */) - { - /* An array of colors to which the image should be dithered */ - png_color std_color_cube[MAX_SCREEN_COLORS]; - - png_set_dither(png_ptr, std_color_cube, MAX_SCREEN_COLORS, - MAX_SCREEN_COLORS, png_uint_16p_NULL, 0); - } - /* This reduces the image to the palette supplied in the file */ - else if (png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette)) - { - png_uint_16p histogram = NULL; - - png_get_hIST(png_ptr, info_ptr, &histogram); - - png_set_dither(png_ptr, palette, num_palette, - max_screen_colors, histogram, 0); - } - } - - /* invert monochrome files to have 0 as white and 1 as black */ - png_set_invert_mono(png_ptr); - - /* If you want to shift the pixel values from the range [0,255] or - * [0,65535] to the original [0,7] or [0,31], or whatever range the - * colors were originally in: - */ - if (png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) - { - png_color_8p sig_bit; - - png_get_sBIT(png_ptr, info_ptr, &sig_bit); - png_set_shift(png_ptr, sig_bit); - } - - /* flip the RGB pixels to BGR (or RGBA to BGRA) */ - if (color_type & PNG_COLOR_MASK_COLOR) - png_set_bgr(png_ptr); - - /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ - png_set_swap_alpha(png_ptr); - - /* swap bytes of 16 bit files to least significant byte first */ - png_set_swap(png_ptr); - - /* Add filler (or alpha) byte (before/after each RGB triplet) */ - png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); - - /* Turn on interlace handling. REQUIRED if you are not using - * png_read_image(). To see how to handle interlacing passes, - * see the png_read_row() method below: - */ - number_passes = png_set_interlace_handling(png_ptr); - - /* Optional call to gamma correct and add the background to the palette - * and update info structure. REQUIRED if you are expecting libpng to - * update the palette for you (ie you selected such a transform above). - */ - png_read_update_info(png_ptr, info_ptr); - - /* Allocate the memory to hold the image using the fields of info_ptr. */ - - /* The easiest way to read the image: */ - png_bytep row_pointers[height]; - - /* Clear the pointer array */ - for (row = 0; row < height; row++) - row_pointers[row] = NULL; - - for (row = 0; row < height; row++) - row_pointers[row] = png_malloc(png_ptr, png_get_rowbytes(png_ptr, - info_ptr)); - - /* Now it's time to read the image. One of these methods is REQUIRED */ -#ifdef entire /* Read the entire image in one go */ - png_read_image(png_ptr, row_pointers); - -#else no_entire /* Read the image one or more scanlines at a time */ - /* The other way to read images - deal with interlacing: */ - - for (pass = 0; pass < number_passes; pass++) - { -#ifdef single /* Read the image a single row at a time */ - for (y = 0; y < height; y++) - { - png_read_rows(png_ptr, &row_pointers[y], png_bytepp_NULL, 1); - } - -#else no_single /* Read the image several rows at a time */ - for (y = 0; y < height; y += number_of_rows) - { -#ifdef sparkle /* Read the image using the "sparkle" effect. */ - png_read_rows(png_ptr, &row_pointers[y], png_bytepp_NULL, - number_of_rows); -#else no_sparkle /* Read the image using the "rectangle" effect */ - png_read_rows(png_ptr, png_bytepp_NULL, &row_pointers[y], - number_of_rows); -#endif no_sparkle /* use only one of these two methods */ - } - - /* if you want to display the image after every pass, do - so here */ -#endif no_single /* use only one of these two methods */ - } -#endif no_entire /* use only one of these two methods */ - - /* read rest of file, and get additional chunks in info_ptr - REQUIRED */ - png_read_end(png_ptr, info_ptr); -#endif hilevel - - /* At this point you have read the entire image */ - - /* clean up after the read, and free any memory allocated - REQUIRED */ - png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); - - /* close the file */ - fclose(fp); - - /* that's it */ - return (OK); -} - -/* progressively read a file */ - -int -initialize_png_reader(png_structp *png_ptr, png_infop *info_ptr) -{ - /* Create and initialize the png_struct with the desired error handler - * functions. If you want to use the default stderr and longjump method, - * you can supply NULL for the last three parameters. We also check that - * the library version is compatible in case we are using dynamically - * linked libraries. - */ - *png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, - png_voidp user_error_ptr, user_error_fn, user_warning_fn); - - if (*png_ptr == NULL) - { - *info_ptr = NULL; - return (ERROR); - } - - *info_ptr = png_create_info_struct(png_ptr); - - if (*info_ptr == NULL) - { - png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL); - return (ERROR); - } - - if (setjmp(png_jmpbuf((*png_ptr)))) - { - png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL); - return (ERROR); - } - - /* This one's new. You will need to provide all three - * function callbacks, even if you aren't using them all. - * If you aren't using all functions, you can specify NULL - * parameters. Even when all three functions are NULL, - * you need to call png_set_progressive_read_fn(). - * These functions shouldn't be dependent on global or - * static variables if you are decoding several images - * simultaneously. You should store stream specific data - * in a separate struct, given as the second parameter, - * and retrieve the pointer from inside the callbacks using - * the function png_get_progressive_ptr(png_ptr). - */ - png_set_progressive_read_fn(*png_ptr, (void *)stream_data, - info_callback, row_callback, end_callback); - - return (OK); -} - -int -process_data(png_structp *png_ptr, png_infop *info_ptr, - png_bytep buffer, png_uint_32 length) -{ - if (setjmp(png_jmpbuf((*png_ptr)))) - { - /* Free the png_ptr and info_ptr memory on error */ - png_destroy_read_struct(png_ptr, info_ptr, png_infopp_NULL); - return (ERROR); - } - - /* This one's new also. Simply give it chunks of data as - * they arrive from the data stream (in order, of course). - * On Segmented machines, don't give it any more than 64K. - * The library seems to run fine with sizes of 4K, although - * you can give it much less if necessary (I assume you can - * give it chunks of 1 byte, but I haven't tried with less - * than 256 bytes yet). When this function returns, you may - * want to display any rows that were generated in the row - * callback, if you aren't already displaying them there. - */ - png_process_data(*png_ptr, *info_ptr, buffer, length); - return (OK); -} - -info_callback(png_structp png_ptr, png_infop info) -{ -/* do any setup here, including setting any of the transformations - * mentioned in the Reading PNG files section. For now, you _must_ - * call either png_start_read_image() or png_read_update_info() - * after all the transformations are set (even if you don't set - * any). You may start getting rows before png_process_data() - * returns, so this is your last chance to prepare for that. - */ -} - -row_callback(png_structp png_ptr, png_bytep new_row, - png_uint_32 row_num, int pass) -{ -/* - * This function is called for every row in the image. If the - * image is interlaced, and you turned on the interlace handler, - * this function will be called for every row in every pass. - * - * In this function you will receive a pointer to new row data from - * libpng called new_row that is to replace a corresponding row (of - * the same data format) in a buffer allocated by your application. - * - * The new row data pointer new_row may be NULL, indicating there is - * no new data to be replaced (in cases of interlace loading). - * - * If new_row is not NULL then you need to call - * png_progressive_combine_row() to replace the corresponding row as - * shown below: - */ - /* Check if row_num is in bounds. */ - if ((row_num >= 0) && (row_num < height)) - { - /* Get pointer to corresponding row in our - * PNG read buffer. - */ - png_bytep old_row = ((png_bytep *)our_data)[row_num]; - - /* If both rows are allocated then copy the new row - * data to the corresponding row data. - */ - if ((old_row != NULL) && (new_row != NULL)) - png_progressive_combine_row(png_ptr, old_row, new_row); - } -/* - * The rows and passes are called in order, so you don't really - * need the row_num and pass, but I'm supplying them because it - * may make your life easier. - * - * For the non-NULL rows of interlaced images, you must call - * png_progressive_combine_row() passing in the new row and the - * old row, as demonstrated above. You can call this function for - * NULL rows (it will just return) and for non-interlaced images - * (it just does the png_memcpy for you) if it will make the code - * easier. Thus, you can just do this for all cases: - */ - - png_progressive_combine_row(png_ptr, old_row, new_row); - -/* where old_row is what was displayed for previous rows. Note - * that the first pass (pass == 0 really) will completely cover - * the old row, so the rows do not have to be initialized. After - * the first pass (and only for interlaced images), you will have - * to pass the current row as new_row, and the function will combine - * the old row and the new row. - */ -} - -end_callback(png_structp png_ptr, png_infop info) -{ -/* this function is called when the whole image has been read, - * including any chunks after the image (up to and including - * the IEND). You will usually have the same info chunk as you - * had in the header, although some data may have been added - * to the comments and time fields. - * - * Most people won't do much here, perhaps setting a flag that - * marks the image as finished. - */ -} - -/* write a png file */ -void write_png(char *file_name /* , ... other image information ... */) -{ - FILE *fp; - png_structp png_ptr; - png_infop info_ptr; - png_colorp palette; - - /* open the file */ - fp = fopen(file_name, "wb"); - if (fp == NULL) - return (ERROR); - - /* Create and initialize the png_struct with the desired error handler - * functions. If you want to use the default stderr and longjump method, - * you can supply NULL for the last three parameters. We also check that - * the library version is compatible with the one used at compile time, - * in case we are using dynamically linked libraries. REQUIRED. - */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, - png_voidp user_error_ptr, user_error_fn, user_warning_fn); - - if (png_ptr == NULL) - { - fclose(fp); - return (ERROR); - } - - /* Allocate/initialize the image information data. REQUIRED */ - info_ptr = png_create_info_struct(png_ptr); - if (info_ptr == NULL) - { - fclose(fp); - png_destroy_write_struct(&png_ptr, png_infopp_NULL); - return (ERROR); - } - - /* Set error handling. REQUIRED if you aren't supplying your own - * error handling functions in the png_create_write_struct() call. - */ - if (setjmp(png_jmpbuf(png_ptr))) - { - /* If we get here, we had a problem reading the file */ - fclose(fp); - png_destroy_write_struct(&png_ptr, &info_ptr); - return (ERROR); - } - - /* One of the following I/O initialization functions is REQUIRED */ -#ifdef streams /* I/O initialization method 1 */ - /* set up the output control if you are using standard C streams */ - png_init_io(png_ptr, fp); -#else no_streams /* I/O initialization method 2 */ - /* If you are using replacement write functions, instead of calling - * png_init_io() here you would call */ - png_set_write_fn(png_ptr, (void *)user_io_ptr, user_write_fn, - user_IO_flush_function); - /* where user_io_ptr is a structure you want available to the callbacks */ -#endif no_streams /* only use one initialization method */ - -#ifdef hilevel - /* This is the easy way. Use it if you already have all the - * image info living info in the structure. You could "|" many - * PNG_TRANSFORM flags into the png_transforms integer here. - */ - png_write_png(png_ptr, info_ptr, png_transforms, png_voidp_NULL); -#else - /* This is the hard way */ - - /* Set the image information here. Width and height are up to 2^31, - * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on - * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY, - * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB, - * or PNG_COLOR_TYPE_RGB_ALPHA. interlace is either PNG_INTERLACE_NONE or - * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST - * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED - */ - png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, PNG_COLOR_TYPE_???, - PNG_INTERLACE_????, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - /* set the palette if there is one. REQUIRED for indexed-color images */ - palette = (png_colorp)png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH - * png_sizeof(png_color)); - /* ... set palette colors ... */ - png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH); - /* You must not free palette here, because png_set_PLTE only makes a link to - the palette that you malloced. Wait until you are about to destroy - the png structure. */ - - /* optional significant bit chunk */ - /* if we are dealing with a grayscale image then */ - sig_bit.gray = true_bit_depth; - /* otherwise, if we are dealing with a color image then */ - sig_bit.red = true_red_bit_depth; - sig_bit.green = true_green_bit_depth; - sig_bit.blue = true_blue_bit_depth; - /* if the image has an alpha channel then */ - sig_bit.alpha = true_alpha_bit_depth; - png_set_sBIT(png_ptr, info_ptr, sig_bit); - - - /* Optional gamma chunk is strongly suggested if you have any guess - * as to the correct gamma of the image. - */ - png_set_gAMA(png_ptr, info_ptr, gamma); - - /* Optionally write comments into the image */ - text_ptr[0].key = "Title"; - text_ptr[0].text = "Mona Lisa"; - text_ptr[0].compression = PNG_TEXT_COMPRESSION_NONE; - text_ptr[1].key = "Author"; - text_ptr[1].text = "Leonardo DaVinci"; - text_ptr[1].compression = PNG_TEXT_COMPRESSION_NONE; - text_ptr[2].key = "Description"; - text_ptr[2].text = ""; - text_ptr[2].compression = PNG_TEXT_COMPRESSION_zTXt; -#ifdef PNG_iTXt_SUPPORTED - text_ptr[0].lang = NULL; - text_ptr[1].lang = NULL; - text_ptr[2].lang = NULL; -#endif - png_set_text(png_ptr, info_ptr, text_ptr, 3); - - /* other optional chunks like cHRM, bKGD, tRNS, tIME, oFFs, pHYs, */ - /* note that if sRGB is present the gAMA and cHRM chunks must be ignored - * on read and must be written in accordance with the sRGB profile */ - - /* Write the file header information. REQUIRED */ - png_write_info(png_ptr, info_ptr); - - /* If you want, you can write the info in two steps, in case you need to - * write your private chunk ahead of PLTE: - * - * png_write_info_before_PLTE(write_ptr, write_info_ptr); - * write_my_chunk(); - * png_write_info(png_ptr, info_ptr); - * - * However, given the level of known- and unknown-chunk support in 1.1.0 - * and up, this should no longer be necessary. - */ - - /* Once we write out the header, the compression type on the text - * chunks gets changed to PNG_TEXT_COMPRESSION_NONE_WR or - * PNG_TEXT_COMPRESSION_zTXt_WR, so it doesn't get written out again - * at the end. - */ - - /* set up the transformations you want. Note that these are - * all optional. Only call them if you want them. - */ - - /* invert monochrome pixels */ - png_set_invert_mono(png_ptr); - - /* Shift the pixels up to a legal bit depth and fill in - * as appropriate to correctly scale the image. - */ - png_set_shift(png_ptr, &sig_bit); - - /* pack pixels into bytes */ - png_set_packing(png_ptr); - - /* swap location of alpha bytes from ARGB to RGBA */ - png_set_swap_alpha(png_ptr); - - /* Get rid of filler (OR ALPHA) bytes, pack XRGB/RGBX/ARGB/RGBA into - * RGB (4 channels -> 3 channels). The second parameter is not used. - */ - png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); - - /* flip BGR pixels to RGB */ - png_set_bgr(png_ptr); - - /* swap bytes of 16-bit files to most significant byte first */ - png_set_swap(png_ptr); - - /* swap bits of 1, 2, 4 bit packed pixel formats */ - png_set_packswap(png_ptr); - - /* turn on interlace handling if you are not using png_write_image() */ - if (interlacing) - number_passes = png_set_interlace_handling(png_ptr); - else - number_passes = 1; - - /* The easiest way to write the image (you may have a different memory - * layout, however, so choose what fits your needs best). You need to - * use the first method if you aren't handling interlacing yourself. - */ - png_uint_32 k, height, width; - png_byte image[height][width*bytes_per_pixel]; - png_bytep row_pointers[height]; - - if (height > PNG_UINT_32_MAX/png_sizeof(png_bytep)) - png_error (png_ptr, "Image is too tall to process in memory"); - - for (k = 0; k < height; k++) - row_pointers[k] = image + k*width*bytes_per_pixel; - - /* One of the following output methods is REQUIRED */ -#ifdef entire /* write out the entire image data in one call */ - png_write_image(png_ptr, row_pointers); - - /* the other way to write the image - deal with interlacing */ - -#else no_entire /* write out the image data by one or more scanlines */ - /* The number of passes is either 1 for non-interlaced images, - * or 7 for interlaced images. - */ - for (pass = 0; pass < number_passes; pass++) - { - /* Write a few rows at a time. */ - png_write_rows(png_ptr, &row_pointers[first_row], number_of_rows); - - /* If you are only writing one row at a time, this works */ - for (y = 0; y < height; y++) - png_write_rows(png_ptr, &row_pointers[y], 1); - } -#endif no_entire /* use only one output method */ - - /* You can write optional chunks like tEXt, zTXt, and tIME at the end - * as well. Shouldn't be necessary in 1.1.0 and up as all the public - * chunks are supported and you can use png_set_unknown_chunks() to - * register unknown chunks into the info structure to be written out. - */ - - /* It is REQUIRED to call this to finish writing the rest of the file */ - png_write_end(png_ptr, info_ptr); -#endif hilevel - - /* If you png_malloced a palette, free it here (don't free info_ptr->palette, - as recommended in versions 1.0.5m and earlier of this example; if - libpng mallocs info_ptr->palette, libpng will free it). If you - allocated it with malloc() instead of png_malloc(), use free() instead - of png_free(). */ - png_free(png_ptr, palette); - palette = NULL; - - /* Similarly, if you png_malloced any data that you passed in with - png_set_something(), such as a hist or trans array, free it here, - when you can be sure that libpng is through with it. */ - png_free(png_ptr, trans); - trans = NULL; - - /* clean up after the write, and free any memory allocated */ - png_destroy_write_struct(&png_ptr, &info_ptr); - - /* close the file */ - fclose(fp); - - /* that's it */ - return (OK); -} - -#endif /* if 0 */ diff --git a/png.c b/png.c index 3067471a2..e1c066690 100644 --- a/png.c +++ b/png.c @@ -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_36rc01 Your_png_h_is_not_version_1_2_36rc01; +typedef version_1_2_36 Your_png_h_is_not_version_1_2_36; /* Version information for C files. This had better match the version * string defined in png.h. */ @@ -694,7 +694,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.36rc01 - April 30, 2009\n\ + return ((png_charp) "\n libpng version 1.2.36 - May 7, 2009\n\ Copyright (c) 1998-2008 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 9af46a21d..267677ad6 100644 --- a/png.h +++ b/png.h @@ -1,6 +1,6 @@ /* png.h - header file for PNG reference library * - * libpng version 1.2.36rc01 - April 30, 2009 + * libpng version 1.2.36 - May 7, 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.36rc01 - April 30, 2009: Glenn + * libpng versions 0.97, January 1998, through 1.2.36 - May 7, 2009: Glenn * See also "Contributing Authors", below. * * Note about libpng version numbers: @@ -224,6 +224,8 @@ * 1.2.35 13 10235 12.so.0.35[.0] * 1.2.36beta01-05 13 10236 12.so.0.36[.0] * 1.2.36rc01 13 10236 12.so.0.36[.0] + * 1.0.44 10 10044 10.so.0.44[.0] + * 1.2.36 13 10236 12.so.0.36[.0] * * Henceforth the source version will match the shared-library major * and minor numbers; the shared-library major version number will be @@ -253,7 +255,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.36rc01, April 30, 2009, are + * libpng versions 1.2.6, August 15, 2004, through 1.2.36, May 7, 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: @@ -365,13 +367,13 @@ * Y2K compliance in libpng: * ========================= * - * April 30, 2009 + * May 7, 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.36rc01 are Y2K compliant. It is my belief that earlier + * upward through 1.2.36 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 @@ -427,9 +429,9 @@ */ /* Version information for png.h - this should match the version in png.c */ -#define PNG_LIBPNG_VER_STRING "1.2.36rc01" +#define PNG_LIBPNG_VER_STRING "1.2.36" #define PNG_HEADER_VERSION_STRING \ - " libpng version 1.2.36rc01 - April 30, 2009\n" + " libpng version 1.2.36 - May 7, 2009\n" #define PNG_LIBPNG_VER_SONUM 0 #define PNG_LIBPNG_VER_DLLNUM 13 @@ -441,7 +443,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 @@ -458,7 +460,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. @@ -1489,7 +1491,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_36rc01; +typedef png_structp version_1_2_36; typedef png_struct FAR * FAR * png_structpp; diff --git a/pngconf.h b/pngconf.h index 1a9fcd7a9..016bd33a7 100644 --- a/pngconf.h +++ b/pngconf.h @@ -1,7 +1,7 @@ /* pngconf.h - machine configurable file for libpng * - * libpng version 1.2.36rc01 - April 30, 2009 + * libpng version 1.2.36 - May 7, 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 fa3f04e25..aa1b5c141 100644 --- a/pngcrush.c +++ b/pngcrush.c @@ -156,7 +156,7 @@ Change log: -Version 1.6.17 (built with libpng-1.2.36rc01 and zlib-1.2.3.2) +Version 1.6.17 (built with libpng-1.2.36and 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. diff --git a/pngdefs.h b/pngdefs.h deleted file mode 100644 index ac36a8582..000000000 --- a/pngdefs.h +++ /dev/null @@ -1,2 +0,0 @@ -/* pngdefs.h was built by makefile.linux */ -#define PNG_NO_MMX_CODE diff --git a/pngerror.c b/pngerror.c index 67d4f5a56..b85ee1165 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.36 [April 30, 2009] + * Last changed in libpng 1.2.36 [May 7, 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/pngpriv.h b/pngpriv.h deleted file mode 100644 index 73fe0cd64..000000000 --- a/pngpriv.h +++ /dev/null @@ -1,908 +0,0 @@ - -/* pngpriv.h - private declarations for use inside libpng - * - * libpng version 1.4.0beta44 - December 6, 2008 - * For conditions of distribution and use, see copyright notice in png.h - * Copyright (c) 1998-2007 Glenn Randers-Pehrson - * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) - * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) - */ - -/* The symbols declared in this file (including the functions declared - * as PNG_EXTERN) are PRIVATE. They are not part of the libpng public - * interface, and are not recommended for use by regular applications. - * Some of them may become public in the future; others may stay private, - * change in an incompatible way, or even disappear. - * Although the libpng users are not forbidden to include this header, - * they should be well aware of the issues that may arise from doing so. - */ - -#ifndef PNGPRIV_H -#define PNGPRIV_H - -#ifndef PNG_VERSION_INFO_ONLY - -#include - -/* The functions exported by PNG_EXTERN are internal functions, which - * aren't usually used outside the library (as far as I know), so it is - * debatable if they should be exported at all. In the future, when it - * is possible to have run-time registry of chunk-handling functions, - * some of these will be made available again. -#define PNG_EXTERN extern - */ -#define PNG_EXTERN - -/* Other defines specific to compilers can go here. Try to keep - * them inside an appropriate ifdef/endif pair for portability. - */ - -#if defined(PNG_FLOATING_POINT_SUPPORTED) -# if defined(MACOS) - /* We need to check that hasn't already been included earlier - * as it seems it doesn't agree with , yet we should really use - * if possible. - */ -# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__) -# include -# endif -# else -# include -# endif -# if defined(_AMIGA) && defined(__SASC) && defined(_M68881) - /* Amiga SAS/C: We must include builtin FPU functions when compiling using - * MATH=68881 - */ -# include -# endif -#endif - -/* Codewarrior on NT has linking problems without this. */ -#if (defined(__MWERKS__) && defined(WIN32)) || defined(__STDC__) -# define PNG_ALWAYS_EXTERN -#endif - -/* This provides the non-ANSI (far) memory allocation routines. */ -#if defined(__TURBOC__) && defined(__MSDOS__) -# include -# include -#endif - -#if defined(WIN32) || defined(_Windows) || defined(_WINDOWS) || \ - defined(_WIN32) || defined(__WIN32__) -# include /* defines _WINDOWS_ macro */ -/* I have no idea why is this necessary... */ -# if defined(_MSC_VER) -# include -# endif -#endif - -/* Various modes of operation. Note that after an init, mode is set to - * zero automatically when the structure is created. - */ -#define PNG_HAVE_IHDR 0x01 -#define PNG_HAVE_PLTE 0x02 -#define PNG_HAVE_IDAT 0x04 -#define PNG_AFTER_IDAT 0x08 /* Have complete zlib datastream */ -#define PNG_HAVE_IEND 0x10 -#define PNG_HAVE_gAMA 0x20 -#define PNG_HAVE_cHRM 0x40 -#define PNG_HAVE_sRGB 0x80 -#define PNG_HAVE_CHUNK_HEADER 0x100 -#define PNG_WROTE_tIME 0x200 -#define PNG_WROTE_INFO_BEFORE_PLTE 0x400 -#define PNG_BACKGROUND_IS_GRAY 0x800 -#define PNG_HAVE_PNG_SIGNATURE 0x1000 -#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */ - -/* flags for the transformations the PNG library does on the image data */ -#define PNG_BGR 0x0001 -#define PNG_INTERLACE 0x0002 -#define PNG_PACK 0x0004 -#define PNG_SHIFT 0x0008 -#define PNG_SWAP_BYTES 0x0010 -#define PNG_INVERT_MONO 0x0020 -#define PNG_DITHER 0x0040 -#define PNG_BACKGROUND 0x0080 -#define PNG_BACKGROUND_EXPAND 0x0100 - /* 0x0200 unused */ -#define PNG_16_TO_8 0x0400 -#define PNG_RGBA 0x0800 -#define PNG_EXPAND 0x1000 -#define PNG_GAMMA 0x2000 -#define PNG_GRAY_TO_RGB 0x4000 -#define PNG_FILLER 0x8000L -#define PNG_PACKSWAP 0x10000L -#define PNG_SWAP_ALPHA 0x20000L -#define PNG_STRIP_ALPHA 0x40000L -#define PNG_INVERT_ALPHA 0x80000L -#define PNG_USER_TRANSFORM 0x100000L -#define PNG_RGB_TO_GRAY_ERR 0x200000L -#define PNG_RGB_TO_GRAY_WARN 0x400000L -#define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */ - /* 0x800000L Unused */ -#define PNG_ADD_ALPHA 0x1000000L /* Added to libpng-1.2.7 */ -#define PNG_EXPAND_tRNS 0x2000000L /* Added to libpng-1.2.9 */ -#define PNG_PREMULTIPLY_ALPHA 0x4000000L /* Added to libpng-1.4.0 by volker */ - /* 0x8000000L unused */ - /* 0x10000000L unused */ - /* 0x20000000L unused */ - /* 0x40000000L unused */ - -/* flags for png_create_struct */ -#define PNG_STRUCT_PNG 0x0001 -#define PNG_STRUCT_INFO 0x0002 - -/* Scaling factor for filter heuristic weighting calculations */ -#define PNG_WEIGHT_SHIFT 8 -#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT)) -#define PNG_COST_SHIFT 3 -#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT)) - -/* flags for the png_ptr->flags rather than declaring a byte for each one */ -#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001 -#define PNG_FLAG_ZLIB_CUSTOM_LEVEL 0x0002 -#define PNG_FLAG_ZLIB_CUSTOM_MEM_LEVEL 0x0004 -#define PNG_FLAG_ZLIB_CUSTOM_WINDOW_BITS 0x0008 -#define PNG_FLAG_ZLIB_CUSTOM_METHOD 0x0010 -#define PNG_FLAG_ZLIB_FINISHED 0x0020 -#define PNG_FLAG_ROW_INIT 0x0040 -#define PNG_FLAG_FILLER_AFTER 0x0080 -#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 -#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 -#define PNG_FLAG_CRC_CRITICAL_USE 0x0400 -#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 -#define PNG_FLAG_FREE_PLTE 0x1000 -#define PNG_FLAG_FREE_TRNS 0x2000 -#define PNG_FLAG_FREE_HIST 0x4000 -#define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000L -#define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000L -#define PNG_FLAG_LIBRARY_MISMATCH 0x20000L -#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000L -#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000L -#define PNG_FLAG_MALLOC_NULL_MEM_OK 0x100000L -#define PNG_FLAG_ADD_ALPHA 0x200000L /* Added to libpng-1.2.8 */ -#define PNG_FLAG_STRIP_ALPHA 0x400000L /* Added to libpng-1.2.8 */ -#define PNG_FLAG_BENIGN_ERRORS_WARN 0x800000L /* Added to libpng-1.4.0 */ - /* 0x1000000L unused */ - /* 0x2000000L unused */ - /* 0x4000000L unused */ - /* 0x8000000L unused */ - /* 0x10000000L unused */ - /* 0x20000000L unused */ - /* 0x40000000L unused */ - -#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ - PNG_FLAG_CRC_ANCILLARY_NOWARN) - -#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \ - PNG_FLAG_CRC_CRITICAL_IGNORE) - -#define PNG_FLAG_CRC_MASK (PNG_FLAG_CRC_ANCILLARY_MASK | \ - PNG_FLAG_CRC_CRITICAL_MASK) - -/* save typing and make code easier to understand */ - -#define PNG_COLOR_DIST(c1, c2) (abs((int)((c1).red) - (int)((c2).red)) + \ - abs((int)((c1).green) - (int)((c2).green)) + \ - abs((int)((c1).blue) - (int)((c2).blue))) - -/* Added to libpng-1.2.6 JB */ -#define PNG_ROWBYTES(pixel_bits, width) \ - ((pixel_bits) >= 8 ? \ - ((png_size_t)(width) * (((png_size_t)(pixel_bits)) >> 3)) : \ - (( ((png_size_t)(width) * ((png_size_t)(pixel_bits))) + 7) >> 3) ) - -/* PNG_OUT_OF_RANGE returns true if value is outside the range - ideal-delta..ideal+delta. Each argument is evaluated twice. - "ideal" and "delta" should be constants, normally simple - integers, "value" a variable. Added to libpng-1.2.6 JB */ -#define PNG_OUT_OF_RANGE(value, ideal, delta) \ - ( (value) < (ideal)-(delta) || (value) > (ideal)+(delta) ) - -/* variables declared in png.c - only it needs to define PNG_NO_EXTERN */ -#if !defined(PNG_NO_EXTERN) || defined(PNG_ALWAYS_EXTERN) -/* place to hold the signature string for a PNG file. */ -#ifdef PNG_USE_GLOBAL_ARRAYS - PNG_EXPORT_VAR (const png_byte FARDATA) png_sig[8]; -#else -#if 0 -#define png_sig png_sig_bytes(NULL) -#endif -#endif -#endif /* PNG_NO_EXTERN */ - -/* Constant strings for known chunk types. If you need to add a chunk, - * define the name here, and add an invocation of the macro in png.c and - * wherever it's needed. - */ -#define PNG_IHDR const png_byte png_IHDR[5] = { 73, 72, 68, 82, '\0'} -#define PNG_IDAT const png_byte png_IDAT[5] = { 73, 68, 65, 84, '\0'} -#define PNG_IEND const png_byte png_IEND[5] = { 73, 69, 78, 68, '\0'} -#define PNG_PLTE const png_byte png_PLTE[5] = { 80, 76, 84, 69, '\0'} -#define PNG_bKGD const png_byte png_bKGD[5] = { 98, 75, 71, 68, '\0'} -#define PNG_cHRM const png_byte png_cHRM[5] = { 99, 72, 82, 77, '\0'} -#define PNG_gAMA const png_byte png_gAMA[5] = {103, 65, 77, 65, '\0'} -#define PNG_hIST const png_byte png_hIST[5] = {104, 73, 83, 84, '\0'} -#define PNG_iCCP const png_byte png_iCCP[5] = {105, 67, 67, 80, '\0'} -#define PNG_iTXt const png_byte png_iTXt[5] = {105, 84, 88, 116, '\0'} -#define PNG_oFFs const png_byte png_oFFs[5] = {111, 70, 70, 115, '\0'} -#define PNG_pCAL const png_byte png_pCAL[5] = {112, 67, 65, 76, '\0'} -#define PNG_sCAL const png_byte png_sCAL[5] = {115, 67, 65, 76, '\0'} -#define PNG_pHYs const png_byte png_pHYs[5] = {112, 72, 89, 115, '\0'} -#define PNG_sBIT const png_byte png_sBIT[5] = {115, 66, 73, 84, '\0'} -#define PNG_sPLT const png_byte png_sPLT[5] = {115, 80, 76, 84, '\0'} -#define PNG_sRGB const png_byte png_sRGB[5] = {115, 82, 71, 66, '\0'} -#define PNG_sTER const png_byte png_sTER[5] = {115, 84, 69, 82, '\0'} -#define PNG_tEXt const png_byte png_tEXt[5] = {116, 69, 88, 116, '\0'} -#define PNG_tIME const png_byte png_tIME[5] = {116, 73, 77, 69, '\0'} -#define PNG_tRNS const png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'} -#define PNG_zTXt const png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'} - -#ifdef PNG_USE_GLOBAL_ARRAYS -PNG_EXPORT_VAR (const png_byte FARDATA) png_IHDR[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_IDAT[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_IEND[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_PLTE[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_bKGD[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_cHRM[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_gAMA[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_hIST[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_iCCP[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_iTXt[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_oFFs[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_pCAL[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_sCAL[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_pHYs[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_sBIT[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_sPLT[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_sRGB[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_tEXt[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_tIME[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_tRNS[5]; -PNG_EXPORT_VAR (const png_byte FARDATA) png_zTXt[5]; -#endif /* PNG_USE_GLOBAL_ARRAYS */ - -/* Inhibit C++ name-mangling for libpng functions but not for system calls. */ -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -/* These functions are used internally in the code. They generally - * shouldn't be used unless you are writing code to add or replace some - * functionality in libpng. More information about most functions can - * be found in the files where the functions are located. - */ - -extern PNG_EXPORT(void,png_read_init_3) PNGARG((png_structpp ptr_ptr, - png_const_charp user_png_ver, png_size_t png_struct_size)); -extern PNG_EXPORT(void,png_write_init_3) PNGARG((png_structpp ptr_ptr, - png_const_charp user_png_ver, png_size_t png_struct_size)); -extern PNG_EXPORT(void,png_write_init_2) PNGARG((png_structp png_ptr, - png_const_charp user_png_ver, png_size_t png_struct_size, png_size_t - png_info_size)); - -/* Allocate memory for an internal libpng struct */ -PNG_EXTERN png_voidp png_create_struct PNGARG((int type)); - -/* Free memory from internal libpng struct */ -PNG_EXTERN void png_destroy_struct PNGARG((png_voidp struct_ptr)); - -PNG_EXTERN png_voidp png_create_struct_2 PNGARG((int type, png_malloc_ptr - malloc_fn, png_voidp mem_ptr)); -PNG_EXTERN void png_destroy_struct_2 PNGARG((png_voidp struct_ptr, - png_free_ptr free_fn, png_voidp mem_ptr)); - -/* Free any memory that info_ptr points to and reset struct. */ -PNG_EXTERN void png_info_destroy PNGARG((png_structp png_ptr, - png_infop info_ptr)); - -/* Function to allocate memory for zlib. PNGAPI is disallowed. */ -PNG_EXTERN voidpf png_zalloc PNGARG((voidpf png_ptr, uInt items, uInt size)); - -/* Function to free memory for zlib. PNGAPI is disallowed. */ -PNG_EXTERN void png_zfree PNGARG((voidpf png_ptr, voidpf ptr)); - -/* Next four functions are used internally as callbacks. PNGAPI is required - * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3. */ - -PNG_EXTERN void PNGAPI png_default_read_data PNGARG((png_structp png_ptr, - png_bytep data, png_size_t length)); - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_EXTERN void PNGAPI png_push_fill_buffer PNGARG((png_structp png_ptr, - png_bytep buffer, png_size_t length)); -#endif - -PNG_EXTERN void PNGAPI png_default_write_data PNGARG((png_structp png_ptr, - png_bytep data, png_size_t length)); - -#if defined(PNG_WRITE_FLUSH_SUPPORTED) -#if !defined(PNG_NO_STDIO) -PNG_EXTERN void PNGAPI png_default_flush PNGARG((png_structp png_ptr)); -#endif -#endif - -/* Reset the CRC variable */ -PNG_EXTERN void png_reset_crc PNGARG((png_structp png_ptr)); - -/* Write the "data" buffer to whatever output you are using */ -PNG_EXTERN void png_write_data PNGARG((png_structp png_ptr, png_bytep data, - png_size_t length)); - -/* Read the chunk header (length + type name) */ -PNG_EXTERN png_uint_32 png_read_chunk_header PNGARG((png_structp png_ptr)); - -/* Read data from whatever input you are using into the "data" buffer */ -PNG_EXTERN void png_read_data PNGARG((png_structp png_ptr, png_bytep data, - png_size_t length)); - -/* Read bytes into buf, and update png_ptr->crc */ -PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf, - png_size_t length)); - -/* Decompress data in a chunk that uses compression */ -#if defined(PNG_zTXt_SUPPORTED) || defined(PNG_iTXt_SUPPORTED) || \ - defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) -PNG_EXTERN void png_decompress_chunk PNGARG((png_structp png_ptr, - int comp_type, png_size_t chunklength, png_size_t prefix_length, - png_size_t *data_length)); -#endif - -/* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ -PNG_EXTERN int png_crc_finish PNGARG((png_structp png_ptr, png_uint_32 skip)); - -/* Read the CRC from the file and compare it to the libpng calculated CRC */ -PNG_EXTERN int png_crc_error PNGARG((png_structp png_ptr)); - -/* Calculate the CRC over a section of data. Note that we are only - * passing a maximum of 64K on systems that have this as a memory limit, - * since this is the maximum buffer size we can specify. - */ -PNG_EXTERN void png_calculate_crc PNGARG((png_structp png_ptr, png_bytep ptr, - png_size_t length)); - -#if defined(PNG_WRITE_FLUSH_SUPPORTED) -PNG_EXTERN void png_flush PNGARG((png_structp png_ptr)); -#endif - -/* write various chunks */ - -/* Write the IHDR chunk, and update the png_struct with the necessary - * information. - */ -PNG_EXTERN void png_write_IHDR PNGARG((png_structp png_ptr, png_uint_32 width, - png_uint_32 height, - int bit_depth, int color_type, int compression_method, int filter_method, - int interlace_method)); - -PNG_EXTERN void png_write_PLTE PNGARG((png_structp png_ptr, png_colorp palette, - png_uint_32 num_pal)); - -PNG_EXTERN void png_write_IDAT PNGARG((png_structp png_ptr, png_bytep data, - png_size_t length)); - -PNG_EXTERN void png_write_IEND PNGARG((png_structp png_ptr)); - -#if defined(PNG_WRITE_gAMA_SUPPORTED) -#ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_EXTERN void png_write_gAMA PNGARG((png_structp png_ptr, double file_gamma)); -#endif -#ifdef PNG_FIXED_POINT_SUPPORTED -PNG_EXTERN void png_write_gAMA_fixed PNGARG((png_structp png_ptr, png_fixed_point - file_gamma)); -#endif -#endif - -#if defined(PNG_WRITE_sBIT_SUPPORTED) -PNG_EXTERN void png_write_sBIT PNGARG((png_structp png_ptr, png_color_8p sbit, - int color_type)); -#endif - -#if defined(PNG_WRITE_cHRM_SUPPORTED) -#ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_EXTERN void png_write_cHRM PNGARG((png_structp png_ptr, - double white_x, double white_y, - double red_x, double red_y, double green_x, double green_y, - double blue_x, double blue_y)); -#endif -PNG_EXTERN void png_write_cHRM_fixed PNGARG((png_structp png_ptr, - png_fixed_point int_white_x, png_fixed_point int_white_y, - png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point - int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, - png_fixed_point int_blue_y)); -#endif - -#if defined(PNG_WRITE_sRGB_SUPPORTED) -PNG_EXTERN void png_write_sRGB PNGARG((png_structp png_ptr, - int intent)); -#endif - -#if defined(PNG_WRITE_iCCP_SUPPORTED) -PNG_EXTERN void png_write_iCCP PNGARG((png_structp png_ptr, - png_charp name, int compression_type, - png_charp profile, int proflen)); - /* Note to maintainer: profile should be png_bytep */ -#endif - -#if defined(PNG_WRITE_sPLT_SUPPORTED) -PNG_EXTERN void png_write_sPLT PNGARG((png_structp png_ptr, - png_sPLT_tp palette)); -#endif - -#if defined(PNG_WRITE_tRNS_SUPPORTED) -PNG_EXTERN void png_write_tRNS PNGARG((png_structp png_ptr, png_bytep trans, - png_color_16p values, int number, int color_type)); -#endif - -#if defined(PNG_WRITE_bKGD_SUPPORTED) -PNG_EXTERN void png_write_bKGD PNGARG((png_structp png_ptr, - png_color_16p values, int color_type)); -#endif - -#if defined(PNG_WRITE_hIST_SUPPORTED) -PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_uint_16p hist, - int num_hist)); -#endif - -#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ - defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) -PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr, - png_charp key, png_charpp new_key)); -#endif - -#if defined(PNG_WRITE_tEXt_SUPPORTED) -PNG_EXTERN void png_write_tEXt PNGARG((png_structp png_ptr, png_charp key, - png_charp text, png_size_t text_len)); -#endif - -#if defined(PNG_WRITE_zTXt_SUPPORTED) -PNG_EXTERN void png_write_zTXt PNGARG((png_structp png_ptr, png_charp key, - png_charp text, png_size_t text_len, int compression)); -#endif - -#if defined(PNG_WRITE_iTXt_SUPPORTED) -PNG_EXTERN void png_write_iTXt PNGARG((png_structp png_ptr, - int compression, png_charp key, png_charp lang, png_charp lang_key, - png_charp text)); -#endif - -#if defined(PNG_TEXT_SUPPORTED) /* Added at version 1.0.14 and 1.2.4 */ -PNG_EXTERN int png_set_text_2 PNGARG((png_structp png_ptr, - png_infop info_ptr, png_textp text_ptr, int num_text)); -#endif - -#if defined(PNG_WRITE_oFFs_SUPPORTED) -PNG_EXTERN void png_write_oFFs PNGARG((png_structp png_ptr, - png_int_32 x_offset, png_int_32 y_offset, int unit_type)); -#endif - -#if defined(PNG_WRITE_pCAL_SUPPORTED) -PNG_EXTERN void png_write_pCAL PNGARG((png_structp png_ptr, png_charp purpose, - png_int_32 X0, png_int_32 X1, int type, int nparams, - png_charp units, png_charpp params)); -#endif - -#if defined(PNG_WRITE_pHYs_SUPPORTED) -PNG_EXTERN void png_write_pHYs PNGARG((png_structp png_ptr, - png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, - int unit_type)); -#endif - -#if defined(PNG_WRITE_tIME_SUPPORTED) -PNG_EXTERN void png_write_tIME PNGARG((png_structp png_ptr, - png_timep mod_time)); -#endif - -#if defined(PNG_WRITE_sCAL_SUPPORTED) -#if defined(PNG_FLOATING_POINT_SUPPORTED) && !defined(PNG_NO_STDIO) -PNG_EXTERN void png_write_sCAL PNGARG((png_structp png_ptr, - int unit, double width, double height)); -#else -#ifdef PNG_FIXED_POINT_SUPPORTED -PNG_EXTERN void png_write_sCAL_s PNGARG((png_structp png_ptr, - int unit, png_charp width, png_charp height)); -#endif -#endif -#endif - -/* Called when finished processing a row of data */ -PNG_EXTERN void png_write_finish_row PNGARG((png_structp png_ptr)); - -/* Internal use only. Called before first row of data */ -PNG_EXTERN void png_write_start_row PNGARG((png_structp png_ptr)); - -#if defined(PNG_READ_GAMMA_SUPPORTED) -PNG_EXTERN void png_build_gamma_table PNGARG((png_structp png_ptr)); -#endif - -/* combine a row of data, dealing with alpha, etc. if requested */ -PNG_EXTERN void png_combine_row PNGARG((png_structp png_ptr, png_bytep row, - int mask)); - -#if defined(PNG_READ_INTERLACING_SUPPORTED) -/* expand an interlaced row */ -/* OLD pre-1.0.9 interface: -PNG_EXTERN void png_do_read_interlace PNGARG((png_row_infop row_info, - png_bytep row, int pass, png_uint_32 transformations)); - */ -PNG_EXTERN void png_do_read_interlace PNGARG((png_structp png_ptr)); -#endif - -/* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ - -#if defined(PNG_WRITE_INTERLACING_SUPPORTED) -/* grab pixels out of a row for an interlaced pass */ -PNG_EXTERN void png_do_write_interlace PNGARG((png_row_infop row_info, - png_bytep row, int pass)); -#endif - -/* unfilter a row */ -PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr, - png_row_infop row_info, png_bytep row, png_bytep prev_row, int filter)); - -/* Choose the best filter to use and filter the row data */ -PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr, - png_row_infop row_info)); - -/* Write out the filtered row. */ -PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr, - png_bytep filtered_row)); -/* finish a row while reading, dealing with interlacing passes, etc. */ -PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr)); - -/* initialize the row buffers, etc. */ -PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr)); -/* optional call to update the users info structure */ -PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr, - png_infop info_ptr)); - -/* these are the functions that do the transformations */ -#if defined(PNG_READ_FILLER_SUPPORTED) -PNG_EXTERN void png_do_read_filler PNGARG((png_row_infop row_info, - png_bytep row, png_uint_32 filler, png_uint_32 flags)); -#endif - -#if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) -PNG_EXTERN void png_do_read_swap_alpha PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#if defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) -PNG_EXTERN void png_do_write_swap_alpha PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) -PNG_EXTERN void png_do_read_invert_alpha PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#if defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) -PNG_EXTERN void png_do_write_invert_alpha PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#if defined(PNG_READ_PREMULTIPLY_ALPHA_SUPPORTED) -PNG_EXTERN void png_do_read_premultiply_alpha PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#if defined(PNG_WRITE_FILLER_SUPPORTED) || \ - defined(PNG_READ_STRIP_ALPHA_SUPPORTED) -PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info, - png_bytep row, png_uint_32 flags)); -#endif - -#if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) -PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, png_bytep row)); -#endif - -#if defined(PNG_READ_PACKSWAP_SUPPORTED) || defined(PNG_WRITE_PACKSWAP_SUPPORTED) -PNG_EXTERN void png_do_packswap PNGARG((png_row_infop row_info, png_bytep row)); -#endif - -#if defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) -PNG_EXTERN int png_do_rgb_to_gray PNGARG((png_structp png_ptr, png_row_infop - row_info, png_bytep row)); -#endif - -#if defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) -PNG_EXTERN void png_do_gray_to_rgb PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#if defined(PNG_READ_PACK_SUPPORTED) -PNG_EXTERN void png_do_unpack PNGARG((png_row_infop row_info, png_bytep row)); -#endif - -#if defined(PNG_READ_SHIFT_SUPPORTED) -PNG_EXTERN void png_do_unshift PNGARG((png_row_infop row_info, png_bytep row, - png_color_8p sig_bits)); -#endif - -#if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) -PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, png_bytep row)); -#endif - -#if defined(PNG_READ_16_TO_8_SUPPORTED) -PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row)); -#endif - -#if defined(PNG_READ_DITHER_SUPPORTED) -PNG_EXTERN void png_do_dither PNGARG((png_row_infop row_info, - png_bytep row, png_bytep palette_lookup, png_bytep dither_lookup)); - -# if defined(PNG_CORRECT_PALETTE_SUPPORTED) -PNG_EXTERN void png_correct_palette PNGARG((png_structp png_ptr, - png_colorp palette, int num_palette)); -# endif -#endif - -#if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) -PNG_EXTERN void png_do_bgr PNGARG((png_row_infop row_info, png_bytep row)); -#endif - -#if defined(PNG_WRITE_PACK_SUPPORTED) -PNG_EXTERN void png_do_pack PNGARG((png_row_infop row_info, - png_bytep row, png_uint_32 bit_depth)); -#endif - -#if defined(PNG_WRITE_SHIFT_SUPPORTED) -PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row, - png_color_8p bit_depth)); -#endif - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) -#if defined(PNG_READ_GAMMA_SUPPORTED) -PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, - png_color_16p trans_color, png_color_16p background, - png_color_16p background_1, - png_bytep gamma_table, png_bytep gamma_from_1, png_bytep gamma_to_1, - png_uint_16pp gamma_16, png_uint_16pp gamma_16_from_1, - png_uint_16pp gamma_16_to_1, int gamma_shift)); -#else -PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, png_bytep row, - png_color_16p trans_color, png_color_16p background)); -#endif -#endif - -#if defined(PNG_READ_GAMMA_SUPPORTED) -PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, png_bytep row, - png_bytep gamma_table, png_uint_16pp gamma_16_table, - int gamma_shift)); -#endif - -#if defined(PNG_READ_EXPAND_SUPPORTED) -PNG_EXTERN void png_do_expand_palette PNGARG((png_row_infop row_info, - png_bytep row, png_colorp palette, png_bytep trans, int num_trans)); -PNG_EXTERN void png_do_expand PNGARG((png_row_infop row_info, - png_bytep row, png_color_16p trans_value)); -#endif - -/* The following decodes the appropriate chunks, and does error correction, - * then calls the appropriate callback for the chunk if it is valid. - */ - -/* decode the IHDR chunk */ -PNG_EXTERN void png_handle_IHDR PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -PNG_EXTERN void png_handle_PLTE PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -PNG_EXTERN void png_handle_IEND PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); - -#if defined(PNG_READ_bKGD_SUPPORTED) -PNG_EXTERN void png_handle_bKGD PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_cHRM_SUPPORTED) -PNG_EXTERN void png_handle_cHRM PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_gAMA_SUPPORTED) -PNG_EXTERN void png_handle_gAMA PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_hIST_SUPPORTED) -PNG_EXTERN void png_handle_hIST PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_iCCP_SUPPORTED) -extern void png_handle_iCCP PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif /* PNG_READ_iCCP_SUPPORTED */ - -#if defined(PNG_READ_iTXt_SUPPORTED) -PNG_EXTERN void png_handle_iTXt PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_oFFs_SUPPORTED) -PNG_EXTERN void png_handle_oFFs PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_pCAL_SUPPORTED) -PNG_EXTERN void png_handle_pCAL PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_pHYs_SUPPORTED) -PNG_EXTERN void png_handle_pHYs PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_sBIT_SUPPORTED) -PNG_EXTERN void png_handle_sBIT PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_sCAL_SUPPORTED) -PNG_EXTERN void png_handle_sCAL PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_sPLT_SUPPORTED) -extern void png_handle_sPLT PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif /* PNG_READ_sPLT_SUPPORTED */ - -#if defined(PNG_READ_sRGB_SUPPORTED) -PNG_EXTERN void png_handle_sRGB PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_tEXt_SUPPORTED) -PNG_EXTERN void png_handle_tEXt PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_tIME_SUPPORTED) -PNG_EXTERN void png_handle_tIME PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_tRNS_SUPPORTED) -PNG_EXTERN void png_handle_tRNS PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -#if defined(PNG_READ_zTXt_SUPPORTED) -PNG_EXTERN void png_handle_zTXt PNGARG((png_structp png_ptr, png_infop info_ptr, - png_uint_32 length)); -#endif - -PNG_EXTERN void png_handle_unknown PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)); - -PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr, - png_bytep chunk_name)); - -/* handle the transformations for reading and writing */ -PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr)); - -PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr)); - -#ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_push_read_sig PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_push_check_crc PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_push_crc_skip PNGARG((png_structp png_ptr, - png_uint_32 length)); -PNG_EXTERN void png_push_crc_finish PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_push_save_buffer PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_push_restore_buffer PNGARG((png_structp png_ptr, - png_bytep buffer, png_size_t buffer_length)); -PNG_EXTERN void png_push_read_IDAT PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_process_IDAT_data PNGARG((png_structp png_ptr, - png_bytep buffer, png_size_t buffer_length)); -PNG_EXTERN void png_push_process_row PNGARG((png_structp png_ptr)); -PNG_EXTERN void png_push_handle_unknown PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)); -PNG_EXTERN void png_push_have_info PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_push_have_end PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_push_have_row PNGARG((png_structp png_ptr, png_bytep row)); -PNG_EXTERN void png_push_read_end PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_process_some_data PNGARG((png_structp png_ptr, - png_infop info_ptr)); -PNG_EXTERN void png_read_push_finish_row PNGARG((png_structp png_ptr)); -#if defined(PNG_READ_tEXt_SUPPORTED) -PNG_EXTERN void png_push_handle_tEXt PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)); -PNG_EXTERN void png_push_read_tEXt PNGARG((png_structp png_ptr, - png_infop info_ptr)); -#endif -#if defined(PNG_READ_zTXt_SUPPORTED) -PNG_EXTERN void png_push_handle_zTXt PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)); -PNG_EXTERN void png_push_read_zTXt PNGARG((png_structp png_ptr, - png_infop info_ptr)); -#endif -#if defined(PNG_READ_iTXt_SUPPORTED) -PNG_EXTERN void png_push_handle_iTXt PNGARG((png_structp png_ptr, - png_infop info_ptr, png_uint_32 length)); -PNG_EXTERN void png_push_read_iTXt PNGARG((png_structp png_ptr, - png_infop info_ptr)); -#endif - -#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ - -#ifdef PNG_MNG_FEATURES_SUPPORTED -PNG_EXTERN void png_do_read_intrapixel PNGARG((png_row_infop row_info, - png_bytep row)); -PNG_EXTERN void png_do_write_intrapixel PNGARG((png_row_infop row_info, - png_bytep row)); -#endif - -#if defined(PNG_MMX_CODE_SUPPORTED) -/* PRIVATE */ -PNG_EXTERN void png_init_mmx_flags PNGARG((png_structp png_ptr)); -#endif - -/* Added at libpng version 1.4.0 */ -#if defined(PNG_cHRM_SUPPORTED) -PNG_EXTERN int png_check_cHRM_fixed PNGARG((png_structp png_ptr, - png_fixed_point int_white_x, png_fixed_point int_white_y, - png_fixed_point int_red_x, png_fixed_point int_red_y, png_fixed_point - int_green_x, png_fixed_point int_green_y, png_fixed_point int_blue_x, - png_fixed_point int_blue_y)); -#endif - -/* Maintainer: Put new private prototypes here ^ and in libpngpf.3 */ - -#ifdef PNG_READ_SUPPORTED -/* Prior to libpng-1.0.9, this block was in pngasmrd.h */ - -/* These are the default thresholds before the MMX code kicks in; if either - * rowbytes or bitdepth is below the threshold, plain C code is used. These - * can be overridden at runtime via the png_set_mmx_thresholds() call in - * libpng 1.2.0 and later. The values below were chosen by Intel. - */ - -#ifndef PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT -# define PNG_MMX_ROWBYTES_THRESHOLD_DEFAULT 128 /* >= */ -#endif -#ifndef PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT -# define PNG_MMX_BITDEPTH_THRESHOLD_DEFAULT 9 /* >= */ -#endif - -/* Set this in the makefile for VC++ on Pentium, not here. */ -/* Platform must be Pentium. Makefile must assemble and load pngvcrd.c . - * MMX will be detected at run time and used if present. - */ -#ifdef PNG_USE_PNGVCRD -# define PNG_HAVE_MMX_COMBINE_ROW -# define PNG_HAVE_MMX_READ_INTERLACE -# define PNG_HAVE_MMX_READ_FILTER_ROW -#endif - -/* Set this in the makefile for gcc/as on Pentium, not here. */ -/* Platform must be Pentium. Makefile must assemble and load pnggccrd.c . - * MMX will be detected at run time and used if present. - */ -#ifdef PNG_USE_PNGGCCRD -# define PNG_HAVE_MMX_COMBINE_ROW -# define PNG_HAVE_MMX_READ_INTERLACE -# define PNG_HAVE_MMX_READ_FILTER_ROW -#endif -/* - see pnggccrd.c for info about what is currently enabled */ - -#endif /* PNG_READ_SUPPORTED */ - -#ifdef __cplusplus -} -#endif - -#endif /* PNG_VERSION_INFO_ONLY */ -#endif /* PNGPRIV_H */ diff --git a/pngrio.c b/pngrio.c index 1e9a809df..d47d86df2 100644 --- a/pngrio.c +++ b/pngrio.c @@ -1,7 +1,7 @@ /* pngrio.c - functions for data input * - * Last changed in libpng 1.2.36 [April 30, 2009] + * Last changed in libpng 1.2.36 [May 7, 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 2ae3d598e..f6f98598f 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.36 [April 30, 2009] + * Last changed in libpng 1.2.36 [May 7, 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 8dc1c6496..9aa29f12e 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.36 [April 30, 2009] + * Last changed in libpng 1.2.36 [May 7, 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 index c903c7ca7..85230f8ad 100644 --- a/pngtest.c +++ b/pngtest.c @@ -1,7 +1,7 @@ /* pngtest.c - a simple test program to test libpng * - * Last changed in libpng 1.2.36 [April 30, 2009] + * Last changed in libpng 1.2.36 [May 7, 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) @@ -1681,4 +1681,4 @@ main(int argc, char *argv[]) } /* Generate a compiler error if there is an old png.h in the search path. */ -typedef version_1_2_36rc01 your_png_h_is_not_version_1_2_36rc01; +typedef version_1_2_36 your_png_h_is_not_version_1_2_36; diff --git a/pngwio.c b/pngwio.c index 9e80cff5c..ab4dba269 100644 --- a/pngwio.c +++ b/pngwio.c @@ -1,7 +1,7 @@ /* pngwio.c - functions for data output * - * Last changed in libpng 1.2.36 [April 30, 2009] + * Last changed in libpng 1.2.36 [May 7, 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 b3d7832f4..3f55f57d1 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 [April 30, 2009] + * Last changed in libpng 1.2.36 [May 7, 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)