diff options
author | Samuli Suominen <drac@gentoo.org> | 2008-07-30 20:07:40 +0000 |
---|---|---|
committer | Samuli Suominen <drac@gentoo.org> | 2008-07-30 20:07:40 +0000 |
commit | 352d27b175122d69bb3522765cd38646f906afe5 (patch) | |
tree | bf7b8649899ef257a6a513db815c3c58a60fdbb0 /media-gfx/pngcrush/files | |
parent | Remove pcre USE flag and add libpcre as unconditional dependency (#233358). (diff) | |
download | gentoo-2-352d27b175122d69bb3522765cd38646f906afe5.tar.gz gentoo-2-352d27b175122d69bb3522765cd38646f906afe5.tar.bz2 gentoo-2-352d27b175122d69bb3522765cd38646f906afe5.zip |
version bump
(Portage version: 2.2_rc3/cvs/Linux 2.6.26-rc3 x86_64)
Diffstat (limited to 'media-gfx/pngcrush/files')
-rw-r--r-- | media-gfx/pngcrush/files/pngcrush-1.6.7-modified_debian_patchset_1.patch | 6072 |
1 files changed, 6072 insertions, 0 deletions
diff --git a/media-gfx/pngcrush/files/pngcrush-1.6.7-modified_debian_patchset_1.patch b/media-gfx/pngcrush/files/pngcrush-1.6.7-modified_debian_patchset_1.patch new file mode 100644 index 000000000000..eaa2328afa1d --- /dev/null +++ b/media-gfx/pngcrush/files/pngcrush-1.6.7-modified_debian_patchset_1.patch @@ -0,0 +1,6072 @@ +diff -ruN pngcrush-1.6.7-nolib.orig/Makefile pngcrush-1.6.7-nolib/Makefile +--- pngcrush-1.6.7-nolib.orig/Makefile 1970-01-01 02:00:00.000000000 +0200 ++++ pngcrush-1.6.7-nolib/Makefile 2008-07-30 23:01:16.000000000 +0300 +@@ -0,0 +1,69 @@ ++# Sample makefile for pngcrush using gcc and GNU make. ++# Glenn Randers-Pehrson ++# Last modified: 19 February 2005 ++# Kapil Hari Paranjape ++# Last modified: 12 June 2008 ++# ++# Invoke this makefile from a shell prompt in the usual way; for example: ++# ++# make -f Makefile ++# ++# This makefile builds a dynamically linked executable. ++ ++# macros -------------------------------------------------------------------- ++ ++GAS_VERSION := $(shell as --version | sed -n -e's/GNU assembler (.*) //p') ++ ++PNGINC = /usr/include ++ ++CC ?= gcc ++RM = rm -f ++ ++CFLAGS += -I. -Wall ++ ++O = .o ++E = ++ ++# additional defines ++DEFINES = -DPNG_USE_PNGGCCRD -DPNG_iCCP_SUPPORTED \ ++ -DPNG_iTXt_SUPPORTED -DPNG_USE_GLOBAL_ARRAYS \ ++ -DGAS_VERSION="\"${GAS_VERSION}\"" \ ++ ++PNGCRUSH = pngcrush ++ ++LIBS = -lpng -lz ++ ++OBJS = pngcrush$(O) ++ ++EXES = $(PNGCRUSH)$(E) ++ ++ ++# implicit make rules ------------------------------------------------------- ++ ++.c$(O): png.h cexcept.h $(ZHDR) ++ $(CC) -c $(CFLAGS) $(DEFINES) $< ++ ++ ++# dependencies -------------------------------------------------------------- ++ ++all: $(EXES) ++ ++png.h: ++ ln -s $(PNGINC)/png.h png.h ++ ++pngcrush$(O): pngcrush.c cexcept.h ++ $(CC) -c $(CFLAGS) $(DEFINES) $< ++ ++$(PNGCRUSH)$(E): $(OBJS) ++ $(CC) $(LDFLAGS) -o $@ $(OBJS) $(LIBS) ++ ++# maintenance --------------------------------------------------------------- ++ ++clean: ++ $(RM) $(EXES) $(OBJS) png.h ++ ++install: ++ mkdir -p $(DESTDIR)/usr/bin/ ++ cp $(PNGCRUSH)$(E) $(DESTDIR)/usr/bin/ ++ chmod 0755 $(DESTDIR)/usr/bin/$(PNGCRUSH)$(E) ++ +diff -ruN pngcrush-1.6.7-nolib.orig/pngcrush.c pngcrush-1.6.7-nolib/pngcrush.c +--- pngcrush-1.6.7-nolib.orig/pngcrush.c 2008-06-13 04:50:52.000000000 +0300 ++++ pngcrush-1.6.7-nolib/pngcrush.c 2008-07-30 22:54:19.000000000 +0300 +@@ -303,6 +303,11 @@ + ((png_uint_32) 116 )) + #endif + ++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_iCCP[5]; ++ + #define PNG_FLAG_CRC_CRITICAL_USE 0x0400 + #define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 + #define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 +@@ -1569,13 +1574,6 @@ + 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); +@@ -2035,7 +2033,7 @@ + if (!strncmp(argv[i], "-zi", 3)) { + text_compression[text_inputs] = + PNG_ITXT_COMPRESSION_zTXt; +- names += 2; ++ /* names += 2; */ + } else + #endif + if (!strncmp(argv[i], "-z", 2)) +@@ -2048,7 +2046,7 @@ + else { + text_compression[text_inputs] = + PNG_ITXT_COMPRESSION_NONE; +- names += 2; ++ /* names += 2; */ + } + #endif + names += 3; +@@ -2062,6 +2060,10 @@ + 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]); +@@ -4698,7 +4700,7 @@ + + for (;;) { + #ifndef PNG_UINT_IDAT +-#ifdef PNG_USE_LOCAL_ARRAYS ++#if defined(PNG_USE_LOCAL_ARRAYS) || defined(PNGCRUSH_USE_LOCAL_ARRAYS) + PNG_IDAT; + PNG_IEND; + PNG_IHDR; +@@ -5452,6 +5454,12 @@ + PNGCRUSH_VERSION, progname, PNG_LIBPNG_VER_STRING, + png_get_header_version(NULL), ZLIB_VERSION); + ++ 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); ++ } ++ + #if defined(__GNUC__) + fprintf(STDERR, + " | It was compiled with gcc version %s", __VERSION__); +diff -ruN pngcrush-1.6.7-nolib.orig/pngcrush.c.orig pngcrush-1.6.7-nolib/pngcrush.c.orig +--- pngcrush-1.6.7-nolib.orig/pngcrush.c.orig 1970-01-01 02:00:00.000000000 +0200 ++++ pngcrush-1.6.7-nolib/pngcrush.c.orig 2008-07-30 22:54:14.000000000 +0300 +@@ -0,0 +1,5915 @@ ++/* pngcrush.c - recompresses png files ++ * Copyright (C) 1998-2002,2006-2008 Glenn Randers-Pehrson (glennrp@users.sf.net) ++ * Copyright (C) 2005 Greg Roelofs ++ * ++ * The most recent version of pngcrush can be found at SourceForge in ++ * http://pmt.sf.net/pngcrush/ ++ * ++ * This program reads in a PNG image, and writes it out again, with the ++ * optimum filter_method and zlib_level. It uses brute force (trying ++ * filter_method none, and libpng adaptive filtering, with compression ++ * levels 3 and 9). It does the most time-consuming method last in case ++ * it turns out to be the best. ++ * ++ * Optionally, it can remove unwanted chunks or add gAMA, sRGB, bKGD, ++ * tEXt/zTXt, and tRNS chunks. It will remove some chunks such as gAMA, ++ * cHRM, pHYs, and oFFs when their data fields contain all zero, which is a ++ * mistake. ++ * ++ * Uses libpng and zlib. This program was based upon libpng's pngtest.c. ++ * ++ * Thanks to Greg Roelofs for various bug fixes, suggestions, and ++ * occasionally creating Linux executables. ++ * ++ * Thanks to Stephan Levavej for some helpful suggestions about gcc compiler ++ * options and for a suggestion to increase the Z_MEM_LEVEL from default. ++ * ++ */ ++ ++#define PNGCRUSH_VERSION "1.6.6" ++ ++/* ++#define PNGCRUSH_COUNT_COLORS ++*/ ++ ++/* ++ * COPYRIGHT NOTICE, DISCLAIMER, AND LICENSE: ++ * ++ * If you have modified this source, you may insert additional notices ++ * immediately after this sentence. ++ * ++ * Copyright (C) 1998-2002,2006-2008 Glenn Randers-Pehrson (glennrp@users.sf.net) ++ * Copyright (C) 2005 Greg Roelofs ++ * ++ * 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. ++ * ++ * Permission is hereby irrevocably granted to everyone to use, copy, modify, ++ * and distribute this source code, or portions hereof, or executable programs ++ * compiled from it, for any purpose, without payment of any fee, subject to ++ * the following restrictions: ++ * ++ * 1. The origin of this source code must not be misrepresented. ++ * ++ * 2. Altered versions must be plainly marked as such and must not be ++ * misrepresented as being the original source. ++ * ++ * 3. This Copyright notice, disclaimer, and license may not be removed ++ * or altered from any source or altered source distribution. ++ */ ++ ++/* To do: ++ * ++ * Reset CINFO to reflect decoder's required window size (instead of ++ * libz-1.1.3 encoder's required window size, which is 262 bytes larger). ++ * See discussion about zlib in png-list archives for April 2001. ++ * ++ * Add a "pcRu" ancillary chunk that keeps track of the best method, ++ * methods already tried, and whether "loco crushing" was effective. ++ * ++ * Try both transformed and untransformed colors when "-loco" is used. ++ * ++ * Check for unused alpha channel and ok-to-reduce-depth. ++ * Take care that sBIT and bKGD data aren't lost when reducing images ++ * from truecolor to grayscale. ++ * ++ * Rearrange palette to put most-used color first and transparent color ++ * second (see ImageMagick 5.1.1 and later). ++ * ++ * Finish pplt (partial palette) feature. ++ * ++ * add "-time" directive ++ * ++ * Allow in-place file replacement or as a filter, as in ++ * "pngcrush -overwrite file.png" ++ * "pngcreator | pngcrush > output.png" ++ * ++ * Use an alternate write function for the trial passes, that ++ * simply counts bytes rather than actually writing to a file, to save wear ++ * and tear on disk drives. ++ * ++ * Remove text-handling and color-handling features and put ++ * those in a separate program or programs, to avoid unnecessary ++ * recompressing. ++ * ++ * Move the Photoshop-fixing stuff into a separate program. ++ * ++ * GRR: More generally (superset of previous 3 items): split into separate ++ * "edit" and "crush" programs (or functions). Former is fully libpng- ++ * aware, much like current pngcrush; latter makes little or no use of ++ * libpng (maybe IDAT-compression parts only?), instead handling virtually ++ * all chunks as opaque binary blocks that are copied to output file _once_, ++ * with IDATs alone replaced (either by best in-memory result or by original ++ * _data_ resplit into bigger IDATs, if pngcrush can't match/beat). "edit" ++ * version should be similar to current code but more efficient: make ++ * _one_ pass through args list, creating table of PNG_UINTs for removal; ++ * then make initial pass through PNG image, creating (in-order) table of ++ * all chunks (and byte offsets?) and marking each as "keep" or "remove" ++ * according to args table. Can start with static table of ~20-30 slots, ++ * then double size & copy if run out of room: still O(n) algorithm. ++ */ ++ ++#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 ++ ++#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_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 ++ ++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_iCCP[5]; ++ ++#define PNG_FLAG_CRC_CRITICAL_USE 0x0400 ++#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 ++#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 ++ * 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 <libc/dosio.h> /* 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 <unistd.h> ++#endif ++ ++#ifndef __riscos ++# include <sys/types.h> ++# include <sys/stat.h> ++# include <utime.h> ++#endif ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <time.h> ++#include <assert.h> ++ ++#if defined(_MBCS) || defined(WIN32) || defined(__WIN32__) ++# include <direct.h> ++#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 <mem.h> ++#endif ++ ++#ifndef CLOCKS_PER_SEC ++#define CLOCKS_PER_SEC 1000 ++#endif ++ ++#if CLOCKS_PER_SEC <= 100 ++# define TIME_T long ++#else ++# define TIME_T float ++#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_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 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); ++ ++png_uint_32 png_get_uint_31(png_structp png_ptr, png_bytep buf); ++png_uint_32 png_get_uint_32(png_bytep buf); ++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 msg) ++{ ++ if (png_ptr); ++#if (defined(PNGCRUSH_H)) ++ if (!strcmp(msg, "Too many IDAT's found")) { ++#ifndef PNG_NO_CONSOLE_IO ++ fprintf(stderr, "\nIn %s, correcting ", inname); ++#else ++ png_warning(png_ptr, msg); ++#endif ++ } else ++#endif /* defined(PNGCRUSH_H) */ ++ { ++ Throw 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 = 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 */ ++ } ++} ++ ++ ++ ++ ++#ifndef __riscos ++# define setfiletype(x) ++ ++#else /* defined(__riscos) */ ++# include <kernel.h> ++ ++/* 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, "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 */ ++ { ++ int lev, strat, filt; ++ 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]); ++ int lev, strat, filt; ++ 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 lev, strat, filt; ++ 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 = 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 */ ++ nosave++; ++ pngcrush_mode = EXTENSION_MODE; ++ } 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], "-rep", 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]); ++ } 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 ++ } ++ } ++#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 lev, strat, filt; ++ 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_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_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))) { ++ png_byte buffer[40]; ++ unsigned long length; ++ /* Skip the MHDR */ ++ png_permit_mng_features(read_ptr, ++ PNG_FLAG_MNG_FILTER_64); ++ png_default_read_data(read_ptr, buffer, 4); ++ length=buffer[3]+(buffer[2]<<8)+(buffer[1]<<16)+(buffer[0]<<24); ++ png_default_read_data(read_ptr, buffer, 4); ++ printf("Skipping %c%c%c%c chunk.\n",buffer[0],buffer[1], ++ buffer[2],buffer[3]); ++ png_default_read_data(read_ptr, buffer, length); ++ png_default_read_data(read_ptr, buffer, 4); ++ 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"); ++ } ++ } ++ ++ 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 ++ * - 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 background = &backgd; ++ background->red = bkgd_red; ++ background->green = bkgd_green; ++ background->blue = bkgd_blue; ++ background->gray = background->green; ++ png_set_bKGD(write_ptr, write_info_ptr, ++ background); ++ } ++ } ++#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)) { ++ if (white_x == 0 && white_y == 0 && red_x == 0 ++ && red_y == 0 && green_x == 0 ++ && green_y == 0 && blue_x == 0 ++ && blue_y == 0) ++ png_warning(write_ptr, ++ "Deleting all-zero cHRM chunk"); ++ else ++ 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)) { ++ if (white_x == 0 && white_y == 0 && red_x == 0 ++ && red_y == 0 && green_x == 0 ++ && green_y == 0 && blue_x == 0 ++ && blue_y == 0) ++ png_warning(write_ptr, ++ "Deleting all-zero cHRM chunk"); ++ else ++ 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 /* defined(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) { ++ int i; ++ 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 ++#if 0 ++ printf(" key=%s.\n",(added_text[0].key)); ++#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; ++ ++ num_unknowns = (int)png_get_unknown_chunks(read_ptr, ++ read_info_ptr, &unknowns); ++ 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; ++ int i; ++ ++ unknowns_keep = 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)) { ++ 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) { ++ int i; ++ ++ 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 buffer[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 */ ++ ++ buffer[0] = (png_byte) ((width >> 24) & 0xff); ++ buffer[1] = (png_byte) ((width >> 16) & 0xff); ++ buffer[2] = (png_byte) ((width >> 8) & 0xff); ++ buffer[3] = (png_byte) ((width) & 0xff); ++ buffer[4] = (png_byte) ((height >> 24) & 0xff); ++ buffer[5] = (png_byte) ((height >> 16) & 0xff); ++ buffer[6] = (png_byte) ((height >> 8) & 0xff); ++ buffer[7] = (png_byte) ((height) & 0xff); ++ for (i = 8; i < 27; i++) ++ buffer[i] = 0x00; ++ buffer[15] = 2; /* layer count */ ++ buffer[19] = 1; /* frame count */ ++ if (output_color_type == 6) ++ buffer[27] = 0x09; /* profile: MNG-VLC with trans. */ ++ else ++ buffer[27] = 0x01; /* profile: MNG-VLC */ ++ png_write_chunk(write_ptr, (png_bytep) png_MHDR, ++ buffer, (png_size_t) 28); ++ } ++#endif /* PNGCRUSH_LOCO */ ++ ++ png_crush_pause(); ++ 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 (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; ++ } ++ } ++ } ++ } ++#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) { ++ int i; ++ 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 (verbose > 0 && 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; ++ utime(outname, &utim); /* set timestamp (no big deal if fails) */ ++#else ++ input_length = (unsigned long) filesize(inname); ++ output_length = (unsigned long) filesize(outname); ++#endif ++ 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 * fpin) ++{ ++ /* 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, fpin); ++#else ++ png_set_read_fn(read_ptr, (png_voidp) fpin, (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 buffer[40]; ++ unsigned long length; ++ /* read the MHDR */ ++ png_default_read_data(read_ptr, buffer, 4); ++ length=buffer[3]+(buffer[2]<<8)+(buffer[1]<<16)+(buffer[0]<<24); ++ png_default_read_data(read_ptr, buffer, 4); ++ printf("Reading %c%c%c%c chunk.\n",buffer[0],buffer[1], ++ buffer[2],buffer[3]); ++ for (b=0; b<40; b++) ++ buffer[b]='\0'; ++ png_default_read_data(read_ptr, buffer, length); ++ if (verbose) { ++ printf(" width=%lu\n",(unsigned long)(buffer[3]+(buffer[2]<<8) ++ +(buffer[1]<<16)+(buffer[0]<<24))); ++ printf(" height=%lu\n",(unsigned long)(buffer[7]+(buffer[6]<<8) ++ +(buffer[5]<<16)+(buffer[4]<<24))); ++ printf(" ticksps=%lu\n",(unsigned long)(buffer[11]+ ++ (buffer[10]<<8)+(buffer[9]<<16)+(buffer[8]<<24))); ++ printf(" nomlayc=%lu\n",(unsigned long)(buffer[15]+ ++ (buffer[14]<<8)+(buffer[13]<<16)+(buffer[12]<<24))); ++ printf(" nomfram=%lu\n",(unsigned long)(buffer[19]+ ++ (buffer[18]<<8)+(buffer[17]<<16)+(buffer[16]<<24))); ++ printf(" nomplay=%lu\n",(unsigned long)(buffer[23]+ ++ (buffer[22]<<8)+(buffer[21]<<16)+(buffer[20]<<24))); ++ printf(" profile=%lu\n",(unsigned long)(buffer[27]+ ++ (buffer[26]<<8)+(buffer[25]<<16)+(buffer[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, ++ buffer, (png_size_t) 28); ++ } ++ ++ png_default_read_data(read_ptr, buffer, 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 ++#if defined(PNG_USE_LOCAL_ARRAYS) || defined(PNGCRUSH_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 buffer[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_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); ++ } ++#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, buffer, 13); ++ length -= 13; ++ input_color_type = buffer[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, buffer, 22); ++ length -= 22; ++ buffer[23] = 0; ++ if (!strncmp((png_const_charp) buffer, "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 ++ return sum_idat_length; ++ } ++ } ++} ++ ++ ++ ++ ++ ++#ifdef PNGCRUSH_COUNT_COLORS ++#define USE_HASHCODE ++int count_colors(FILE * fpin) ++{ ++ /* 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, fpin); ++#else ++ png_set_read_fn(read_ptr, (png_voidp) fpin, (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 */ ++ png_default_read_data(read_ptr, buffer, 4); ++ length=buffer[3]+(buffer[2]<<8)+(buffer[1]<<16)+(buffer[0]<<24); ++ png_default_read_data(read_ptr, buffer, 4); ++ printf("Skipping %c%c%c%c chunk.\n",buffer[0],buffer[1], ++ buffer[2],buffer[3]); ++ png_default_read_data(read_ptr, buffer, length); ++ png_default_read_data(read_ptr, buffer, 4); ++ 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"); ++ } ++ } ++ 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-2008 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-2008 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-2008 Glenn Randers-Pehrson (glennrp@users.sf.net)", ++ "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 ++ ++ ++#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, " -n (no save; does not 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. Please don't use "}, ++ {2, " this 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 gAMA is present."}, ++#else ++ {0, "-replace_gamma gamma (float, e.g. 0.45455) even if gAMA 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 images"}, ++ {2, " (and quite effective on black-and-white images),"}, ++ {2, " but not necessarily worth the bother 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, " -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); ++} |