diff options
author | Glenn Randers-Pehrson <glennrp at users.sourceforge.net> | 2013-02-10 07:49:35 -0600 |
---|---|---|
committer | Glenn Randers-Pehrson <glennrp at users.sourceforge.net> | 2013-02-10 07:51:15 -0600 |
commit | acde3d47005b9cd7723de3c63c19534a1c3671d5 (patch) | |
tree | 8f12080cd587c9f5b64a7257a63b9d7fb3ba7a80 | |
parent | dcd877e37ce0267cdd699b6faaf3c11035d9b1c7 (diff) | |
download | libpng-1.7.48.tar.gz |
Imported from pngcrush-1.7.48.tarv1.7.48
-rw-r--r-- | ChangeLog.html | 26 | ||||
-rw-r--r-- | Makefile | 2 | ||||
-rw-r--r-- | pngconf.h | 1 | ||||
-rw-r--r-- | pngcrush.c | 1040 | ||||
-rw-r--r-- | pngcrush.h | 10 |
5 files changed, 273 insertions, 806 deletions
diff --git a/ChangeLog.html b/ChangeLog.html index 4a7d4ee80..c0ba5cc4a 100644 --- a/ChangeLog.html +++ b/ChangeLog.html @@ -3,14 +3,40 @@ Change log: +Version 1.7.48 (built with libpng-1.5.14 and zlib-1.2.7) + Reserved method==0 for examining the pixels during trial 0, if necessary. + Changed blacken_fn() to separate pngcrush_examine_pixels_fn() and + pngcrush_transform_pixels_fn() callback functions. The "examine" + function is only done during trial 0; it sets a flag whether + any fully transparent pixels were found, and pngcrush only runs + pngcrush_transform_pixels_fn() if necessary. + This is in preparation for future versions, which will examine other + conditions such as if the image is opaque or gray or can be losslessly + reduced in bit depth, set flags in trial 0 and accomplish the + transformations in the remaining trials (see the To do list starting + about line 188 in the pngcrush.c source). + Removed "PNGCRUSH_COUNT_COLORS" blocks again. + +Version 1.7.47 (built with libpng-1.5.13 and zlib-1.2.7) + Do not do the heuristic trials of the first 10 methods when -brute is + specified, because it did not save time as I hoped. + Fixed a mistake in 1.7.45 and 1.7.46 that caused the output file to + not be written. + +Version 1.7.46 (built with libpng-1.5.13 and zlib-1.2.7) + Moved the new level 0 methods to the end of the trial list (methods 137-148) + Version 1.7.45 (built with libpng-1.5.13 and zlib-1.2.7) Added method 0 (uncompressed). "-m 0" now simply turns on method 0. Added "-try10" option that has the same effect that "-m 0" previously did, namely to try only the first ten methods. + Inserted new methods 17 through 21 with zlib level 0. Do the heuristic trials of the first 10 methods when -brute is specified, to get quickly to a small solution, so we can bail out of most of the remaining trials early. Previously these 10 methods were skipped during a -brute run. + Removed the "-reduce" line from the help screen when PNGCRUSH_COUNT_COLORS + is disabled. Version 1.7.44 (built with libpng-1.5.14 and zlib-1.2.7) @@ -62,7 +62,7 @@ EXES = $(PNGCRUSH)$(E) # implicit make rules ------------------------------------------------------- -.c$(O): png.h pngconf.h pngcrush.h cexcept.h pngpriv.h $(ZHDR) +.c$(O): png.h pngconf.h pngcrush.h cexcept.h pngpriv.h pnglibconf.h $(ZHDR) $(CC) -c $(TOOFAR_OK) $(CPPFLAGS) $(CFLAGS) $< @@ -13,7 +13,6 @@ * * This file has been modified, by Glenn Randers-Pehrson, from the original * libpng distribution by adding a line reading - * * #include "pngcrush.h" */ diff --git a/pngcrush.c b/pngcrush.c index b584cd9af..e8a1ece11 100644 --- a/pngcrush.c +++ b/pngcrush.c @@ -80,7 +80,7 @@ * */ -#define PNGCRUSH_VERSION "1.7.47" +#define PNGCRUSH_VERSION "1.7.48" /* Experimental: define these if you wish, but, good luck. #define PNGCRUSH_COUNT_COLORS @@ -152,18 +152,22 @@ * the image (note that libpng-based decoders don't make use of this * hint until libpng-1.6.0). * - * In the meantime, one can just do the following and select the smallest - * window that does not increase the filesize, after running pngcrush once - * and observing what was the best pngcrush method: + * In the meantime, one can just run * - * for w in 32 16 8 4 2 1 512 + * pc input.png crushed.png + * + * where the "pc" script is the following: + * + * #!/bin/sh + * cp $1 temp-$$.png + * for w in 512 1 2 4 8 16 32 * do - * pngcrush -m <best_pngcrush_method> -w $w $1 w-$w.png + * pngcrush -ow -w $w -brute temp-$$.png * done + * mv temp-$$.png $2 * - * then use pngcheck -v and look at the IDAT report to find out what window - * size is actually set in a png file (or revise pngcrush -v to report - * the window size). + * It turns out that sometimes this finds a smaller compressed PNG + * than plain "pngcrush -brute input.png crushed.png" finds. * * There are several ways that pngcrush could implement this. * @@ -185,6 +189,10 @@ * solution; however, it will only work with libpng-1.6.0 and later, * where the decoder actually uses the CINFO hint. * + * d. The simplest way might be to simply try all window sizes + * for all methods, just as the "pc" script above does. This of + * course involves a lot more trial compressions. + * * 2. Check for unused alpha channel in color-type 4 and 6. * * a. If the image is entirely opaque, reduce the color-type to 0 or 2. @@ -213,14 +221,14 @@ * become invalid when reducing images from truecolor to grayscale or * when reducing the bit depth. * + * See pngcrush_examine_pixels_fn() and pngcrush_transform_pixels_fn(), + * below. + * * 5. Add choice of interlaced or non-interlaced output. Currently you * can change interlaced to non-interlaced and vice versa by using * ImageMagick before running pngcrush. * - * 6. Find out why the "-nobail" option is faster than "-bail". For now, - * make "-nobail" the default. - * - * 7. Use a better compression algorithm for "deflating" (result must + * 6. Use a better compression algorithm for "deflating" (result must * still be readable with zlib!) e.g., http://en.wikipedia.org/wiki/7-Zip * says that the 7-zip deflate compressor achieves better compression * (smaller files) than zlib. If tests show that this would be worth @@ -230,7 +238,7 @@ * is incorporated in pngcrush, then pngcrush would have to be re-licensed, * or released in two versions, one libpng-licensed and one GPL-licensed! * - * 8. Implement palette-building (from ImageMagick-6.7.0 or later, minus + * 7. Implement palette-building (from ImageMagick-6.7.0 or later, minus * the "PNG8" part) -- actually ImageMagick puts the transparent colors * first, then the semitransparent colors, and finally the opaque colors, * and does not sort colors by frequency of use but just adds them @@ -241,30 +249,30 @@ * package which counts RGB pixels in an image; this and its supporting * lib/libppmcmap.c would need to be revised to count RGBA pixels instead. * - * 9. Check the "-plte_len n" option to be sure that no pixel contains + * 8. Check the "-plte_len n" option to be sure that no pixel contains * an index value that is out of range due to truncation of the PLTE chunk. * Implementing item "7" will take care of this, since that will always * build a palette of the right length, and the -plte_len option can be * eliminated. * - * 10. Improve the -help output and/or write a good man page. + * 9. Improve the -help output and/or write a good man page. * - * 11. Finish pplt (MNG partial palette) feature. + * 10. Finish pplt (MNG partial palette) feature. * - * 12. Remove text-handling and color-handling features and put + * 11. Remove text-handling and color-handling features and put * those in a separate program or programs, to avoid unnecessary * recompressing. Note that in pngcrush-1.7.34, pngcrush began doing * this extra work only once instead of for every trial, so the potential * benefit in CPU savings is much smaller now. * - * 13. Add a "pcRu" ancillary chunk that keeps track of the best method, + * 12. Add a "pcRu" ancillary chunk that keeps track of the best method, * methods already tried, and whether "loco crushing" was effective. * - * 14. Try both transformed and untransformed colors when "-loco" is used. + * 13. Try both transformed and untransformed colors when "-loco" is used. * - * 15. Move the Photoshop-fixing stuff into a separate program. + * 14. Move the Photoshop-fixing stuff into a separate program. * - * 16. GRR: More generally (superset of previous 3 items): split into + * 15. 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 @@ -284,6 +292,20 @@ Change log: +Version 1.7.48 (built with libpng-1.5.14 and zlib-1.2.7) + Reserved method==0 for examining the pixels during trial 0, if necessary. + Changed blacken_fn() to separate pngcrush_examine_pixels_fn() and + pngcrush_transform_pixels_fn() callback functions. The "examine" + function is only done during trial 0; it sets a flag whether + any fully transparent pixels were found, and pngcrush only runs + pngcrush_transform_pixels_fn() if necessary. + This is in preparation for future versions, which will examine other + conditions such as if the image is opaque or gray or can be losslessly + reduced in bit depth, set flags in trial 0 and accomplish the + transformations in the remaining trials (see the To do list starting + about line 188 in the pngcrush.c source). + Removed "PNGCRUSH_COUNT_COLORS" blocks again. + Version 1.7.47 (built with libpng-1.5.13 and zlib-1.2.7) Do not do the heuristic trials of the first 10 methods when -brute is specified, because it did not save time as I hoped. @@ -1045,7 +1067,7 @@ Version 1.1.4: added ability to restrict brute_force to one or more filter # endif #endif -#if PNGCRUSH_LIBPNG_VER < 10600 || defined(PNGCRUSH_H) +#if PNGCRUSH_LIBPNG_VER < 10700 || defined(PNGCRUSH_H) /* Changed in version 0.99 */ #if PNGCRUSH_LIBPNG_VER < 99 @@ -1294,7 +1316,7 @@ png_uint_32 pngcrush_crc; #define STR_BUF_SIZE 256 #define MAX_IDAT_SIZE 524288L -#define MAX_METHODS 200 +#define MAX_METHODS 150 #define MAX_METHODSP1 (MAX_METHODS+1) #define DEFAULT_METHODS 10 #define FAKE_PAUSE_STRING "P" @@ -1430,6 +1452,7 @@ static int blacken = 0; /* if 0, or 1 after the first trial, do not blacken color samples */ static int things_have_changed = 0; static int global_things_have_changed = 0; +static int compression_window; static int default_compression_window = 15; static int force_compression_window = 0; static int compression_mem_level = 9; @@ -1514,11 +1537,6 @@ static int input_format = 0; /* 0: PNG 1: MNG */ static int output_format = 0; #endif static int do_color_count; -#ifdef PNGCRUSH_COUNT_COLORS -static int reduction_ok = 0; -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]; @@ -1617,9 +1635,6 @@ void show_result(void); png_uint_32 measure_idats(FILE * fp); 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); @@ -2356,86 +2371,171 @@ static void pngcrush_flush(png_structp png_ptr) } -void blacken_fn(png_structp png_ptr, png_row_infop row_info, png_bytep data) +void pngcrush_examine_pixels_fn(png_structp png_ptr, png_row_infop + row_info, png_bytep data) { - /* change the underlying color of any fully transparent pixels to black */ int i; - if (row_info->color_type < 4) - return; - - i=(int) row_info->rowbytes-1; - - if (row_info->color_type == 4) /* GA */ + if (blacken == 1) { - if (row_info->bit_depth == 8) - { - for ( ; i > 0 ; ) - { - if (data[i] == 0 && data[i-1] != 0) - { - data[i-1]=0; - blacken = 2; - } - i-=2; - } - } - - else /* bit depth == 16 */ - { - for ( ; i > 0 ; ) - { - if ((data[i] == 0 && data[i-1] == 0) && (data[i-2] != 0 || - data[i-3] != 0)) - { - data[i-2]=0; - data[i-3]=0; - blacken = 2; - } - i-=4; - } - } + /* Check if there are any fully transparent pixels. If one is found, + * set blacken==2 and do not check any more pixels. If the PNG + * colortype does not support an alpha channel, set blacken==0 + * and do not check any more rows. + */ + + if (row_info->color_type < 4) + blacken = 0; + + i=(int) row_info->rowbytes-1; + + if (row_info->color_type == 4) /* GA */ + { + if (row_info->bit_depth == 8) + { + for ( ; i > 0 ; ) + { + if (data[i] == 0 && data[i-1] != 0) + { + blacken = 2; + } + i-=2; + } + } + + else /* bit depth == 16 */ + { + for ( ; i > 0 ; ) + { + if ((data[i] == 0 && data[i-1] == 0) && (data[i-2] != 0 || + data[i-3] != 0)) + { + blacken = 2; + } + i-=4; + } + } + } + + else /* color_type == 6, RGBA */ + { + if (row_info->bit_depth == 8) + { + for ( ; i > 0 ; ) + { + if (data[i] == 0 && (data[i-1] != 0 || data[i-2] != 0 || + data[i-3] != 0)) + { + blacken = 2; + } + i-=4; + } + } + + else /* bit depth == 16 */ + { + for ( ; i > 0 ; ) + { + if ((data[i]==0 && data[i-1]== 0) && + (data[i-2] != 0 || data[i-3] != 0 || data[i-4] != 0 || + data[i-5] != 0 || data[i-6] != 0 || data[i-7] != 0)) + { + blacken = 2; + } + i-=8; + } + } + } } - else /* color_type == 6, RGBA */ + /* Future versions will check here for other conditions such as whether + * the image has an all-opaque alpha channel or if all pixels are gray. + */ +} + +void pngcrush_transform_pixels_fn(png_structp png_ptr, png_row_infop row_info, + png_bytep data) +{ + + int i; + + if (blacken == 2) { - if (row_info->bit_depth == 8) - { - for ( ; i > 0 ; ) - { - if (data[i] == 0 && (data[i-1] != 0 || data[i-2] != 0 || - data[i-3] != 0)) - { - data[i-1]=0; - data[i-2]=0; - data[i-3]=0; - blacken = 2; - } - i-=4; - } - } - - else /* bit depth == 16 */ - { - for ( ; i > 0 ; ) - { - if ((data[i]==0 && data[i-1]== 0) && - (data[i-2] != 0 || data[i-3] != 0 || data[i-4] != 0 || - data[i-5] != 0 || data[i-6] != 0 || data[i-7] != 0)) - { - data[i-2]=0; - data[i-3]=0; - data[i-4]=0; - data[i-5]=0; - data[i-6]=0; - data[i-7]=0; - blacken = 2; - } - i-=8; - } - } + /* change the underlying color of any fully transparent pixels to black */ + i=(int) row_info->rowbytes-1; + + if (row_info->color_type == 4) /* GA */ + { + if (row_info->bit_depth == 8) + { + for ( ; i > 0 ; ) + { + if (data[i] == 0 && data[i-1] != 0) + { + data[i-1]=0; + } + i-=2; + } + } + + else /* bit depth == 16 */ + { + for ( ; i > 0 ; ) + { + if ((data[i] == 0 && data[i-1] == 0) && (data[i-2] != 0 || + data[i-3] != 0)) + { + data[i-2]=0; + data[i-3]=0; + } + i-=4; + } + } + } + + else /* color_type == 6, RGBA */ + { + if (row_info->bit_depth == 8) + { + for ( ; i > 0 ; ) + { + if (data[i] == 0 && (data[i-1] != 0 || data[i-2] != 0 || + data[i-3] != 0)) + { + data[i-1]=0; + data[i-2]=0; + data[i-3]=0; + } + i-=4; + } + } + + else /* bit depth == 16 */ + { + for ( ; i > 0 ; ) + { + if ((data[i]==0 && data[i-1]== 0) && + (data[i-2] != 0 || data[i-3] != 0 || data[i-4] != 0 || + data[i-5] != 0 || data[i-6] != 0 || data[i-7] != 0)) + { + data[i-2]=0; + data[i-3]=0; + data[i-4]=0; + data[i-5]=0; + data[i-6]=0; + data[i-7]=0; + } + i-=8; + } + } + } } + + /* Future versions will make other transformations such as removing + * an all-opaque alpha channel or changing RGB to gray if all pixels + * are gray. + */ } @@ -2469,13 +2569,8 @@ int main(int argc, char *argv[]) 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)) { @@ -2661,8 +2756,7 @@ int main(int argc, char *argv[]) { methods_specified = 1; brute_force++; - try_method[0] = 0; /* uncompressed */ - for (method = 0; method < num_methods; method++) + for (method = 1; method < num_methods; method++) try_method[method] = 0; if (brute_force_filter == 0) for (filt = 0; filt < 6; filt++) @@ -2995,10 +3089,7 @@ int main(int argc, char *argv[]) } else if (!strncmp(argv[i], "-reduce", 7)) { -#ifdef PNGCRUSH_COUNT_COLORS - reduction_ok++; - do_color_count = 1; -#endif + /* unused */ } #ifdef PNG_gAMA_SUPPORTED else if (!strncmp(argv[i], "-replace_gamma", 4)) @@ -3351,7 +3442,7 @@ int main(int argc, char *argv[]) for (;;) /* loop on input files */ { - last_trial = 1; + last_trial = 0; things_have_changed = global_things_have_changed; @@ -3610,86 +3701,9 @@ int main(int argc, char *argv[]) } 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 */ - { - /* TO DO */ - } - - 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 /* 0, TODO */ - 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 not supported.\n"); -#endif /* PNGCRUSH_COUNT_COLORS */ if (plte_len > 0 && force_output_bit_depth == 0) { @@ -3737,8 +3751,11 @@ int main(int argc, char *argv[]) best_of_three = 1; - if (blacken > 1) + if (blacken) + { blacken = 1; + try_method[0] = 0; + } /* //////////////////////////////////////////////////////////////////// //////////////// //////////////////// @@ -3755,7 +3772,8 @@ int main(int argc, char *argv[]) pngcrush_write_byte_count=0; - idat_length[trial] = (png_uint_32) 0xffffffff; + if (trial > 1) + idat_length[trial] = (png_uint_32) 0xffffffff; /* this part of if-block is for final write-the-best-file iteration */ @@ -3991,8 +4009,17 @@ int main(int argc, char *argv[]) #endif /* 0 */ /* Change the underlying color of any fully transparent pixel to black */ - if ((trial == 0 && blacken == 1) || blacken == 2) - png_set_read_user_transform_fn(read_ptr, blacken_fn); + if (trial == 0 && blacken == 1) + { + P1(" Check for fully transparent pixels\n"); + png_set_read_user_transform_fn(read_ptr, pngcrush_examine_pixels_fn); + } + + if (trial != 0 && blacken == 2) + { + P1(" Blacken the fully transparent pixels\n"); + png_set_read_user_transform_fn(read_ptr, pngcrush_transform_pixels_fn); + } #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED if (last_trial == 0) @@ -4374,12 +4401,6 @@ int main(int argc, char *argv[]) { if (verbose > 0 && last_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"); } @@ -4417,14 +4438,8 @@ int main(int argc, char *argv[]) { if (verbose > 0 && last_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"); + fprintf(STDERR, + " Stripping existing alpha channel.\n"); } #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED png_set_strip_alpha(read_ptr); @@ -5502,7 +5517,6 @@ int main(int argc, char *argv[]) pngcrush_pause(); { - int compression_window; png_uint_32 zbuf_size; png_uint_32 required_window; int channels = 0; @@ -6077,6 +6091,9 @@ int main(int argc, char *argv[]) if (nosave) break; + if (trial == 0) + continue; + idat_length[trial] = pngcrush_write_byte_count; if (pngcrush_write_byte_count < pngcrush_best_byte_count) @@ -6087,15 +6104,17 @@ int main(int argc, char *argv[]) if (bail==0 && pngcrush_write_byte_count > pngcrush_best_byte_count) fprintf(STDERR, - " Critical chunk length with method %3d" - " (fm %d zl %d zs %d) > %8lu\n", - trial, filter_type, zlib_level, z_strategy, + " Critical chunk length, method %3d" + " (ws %d fm %d zl %d zs %d) > %8lu\n", + trial, compression_window, + filter_type, zlib_level, z_strategy, (unsigned long)pngcrush_best_byte_count); else fprintf(STDERR, - " Critical chunk length with method %3d" - " (fm %d zl %d zs %d) = %8lu\n", - trial, filter_type, zlib_level, z_strategy, + " Critical chunk length, method %3d" + " (ws %d fm %d zl %d zs %d) = %8lu\n", + trial, compression_window, + filter_type, zlib_level, z_strategy, (unsigned long)idat_length[trial]); fflush(STDERR); } @@ -6174,8 +6193,10 @@ int main(int argc, char *argv[]) else if (!already_crushed && !image_is_immutable) { fprintf(STDERR, - " Best pngcrush method = %d (fm %d zl %d zs %d)\n" - " for %s\n", best, fm[best], lv[best], zs[best], outname); + " Best pngcrush method = %d " + "(ws %d fm %d zl %d zs %d) = %8lu\n for %s\n", best, + compression_window, fm[best], lv[best], zs[best], + (unsigned long)idat_length[best], outname); } if (idat_length[0] == idat_length[best]) @@ -6660,575 +6681,6 @@ png_uint_32 png_measure_idat(png_structp png_ptr) } - - - -#ifdef PNGCRUSH_COUNT_COLORS -#define USE_HASHCODE -int count_colors(FILE * fp_in) -{ - /* Copyright (C) 2000-2002, 2006-2013 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; - -#ifdef PNG_STDIO_SUPPORTED - png_init_io(read_ptr, fp_in); -#else - png_set_read_fn(read_ptr, (png_voidp) fp_in, (png_rw_ptr) NULL); -#endif - - { -#ifdef 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 }; - - pngcrush_default_read_data(read_ptr, png_signature, 8); - png_set_sig_bytes(read_ptr, 8); - -#ifdef PNGCRUSH_LOCO - if (!(int) (png_memcmp(mng_signature, png_signature, 8))) { - png_byte buffer[40]; - unsigned long length; - /* Skip the MHDR chunk. */ - png_skip_chunk(read_ptr); - png_permit_mng_features(read_ptr, - PNG_FLAG_MNG_FILTER_64); - input_format = 1; - } - else -#endif - if (png_sig_cmp(png_signature, 0, 8)) - { - if (png_sig_cmp(png_signature, 0, 4)) - png_error(read_ptr, "Not a PNG file."); - else - png_error(read_ptr, - "PNG file corrupted by ASCII conversion"); - } - } - - if (fix && found_CgBI) - { - /* Skip the CgBI chunk. */ - png_skip_chunk(read_ptr); - /* iCCP is probably badly compressed */ - png_set_keep_unknown_chunks(read_ptr, - PNG_HANDLE_CHUNK_NEVER, - (png_bytep)"iCCP", 1); -#ifdef PNG_iTXt_SUPPORTED - /* and iTXt */ - png_set_keep_unknown_chunks(read_ptr, - PNG_HANDLE_CHUNK_NEVER, - (png_bytep)"iTXt", 1); -#endif - /* zTXt too */ - png_set_keep_unknown_chunks(read_ptr, - PNG_HANDLE_CHUNK_NEVER, - (png_bytep)"zTXt", 1); - } - - png_read_info(read_ptr, read_info_ptr); - -#ifdef PNG_CRC_QUIET_USE - png_set_crc_action(read_ptr, PNG_CRC_QUIET_USE, - PNG_CRC_QUIET_USE); -#endif - - png_get_IHDR(read_ptr, read_info_ptr, &width, &height, - &bit_depth, &color_type, &interlace_method, - &compression_method, &filter_method); - - if (color_type == 2) - channels = 3; - else if (color_type == 4) - channels = 2; - else if (color_type == 6) - channels = 4; - else - channels = 1; - - if (color_type == 0 || color_type == 3 || color_type == 4) - reduce_to_gray = 1; - - if (bit_depth == 8) - { - if (interlace_method) - num_pass = 7; - else - num_pass = 1; - - rowbytes = png_get_rowbytes(read_ptr, read_info_ptr); - - row_buf = png_malloc(read_ptr, rowbytes + 64); - - 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) { char *zlib_copyright; @@ -7400,11 +6852,6 @@ struct options_help pngcrush_options[] = { {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"}, @@ -7539,11 +6986,6 @@ struct options_help pngcrush_options[] = { {2, " exact filesize achieved by each trial."}, {2, ""}, -#ifdef PNGCRUSH_COUNT_COLORS - {0, " -no_cc (no color counting)"}, - {2, ""}, -#endif - {0, " -nofilecheck (do not check for infile.png == outfile.png)"}, {2, ""}, {2, " To avoid false hits from MSVC-compiled code. Note"}, @@ -7793,4 +7235,4 @@ void print_usage(int retval) exit(retval); } -#endif /* PNGCRUSH_LIBPNG_VER < 10600 || defined(PNGCRUSH_H) */ +#endif /* PNGCRUSH_LIBPNG_VER < 10700 || defined(PNGCRUSH_H) */ diff --git a/pngcrush.h b/pngcrush.h index 7fe298b29..c835a0f6e 100644 --- a/pngcrush.h +++ b/pngcrush.h @@ -5,15 +5,16 @@ * license (see LICENSE, in pngcrush.c). */ -/* Special defines for pngcrush. */ +/* Special defines for pngcrush version 1.7.48 */ #ifndef PNGCRUSH_H #define PNGCRUSH_H /* This allows png_default_error() to return, when it is called after our - own exception handling, which only returns after "Too many IDAT's", - or anything else that we might want to handle as a warning instead of - an error. */ + * own exception handling, which only returns after "Too many IDAT's", + * or anything else that we might want to handle as a warning instead of + * an error. + */ #if PNGCRUSH_LIBPNG_VER >= 10700 # define PNG_ABORT exit(1) @@ -23,6 +24,5 @@ /* Suppress libpng pedantic warnings */ #define PNG_NORETURN /* This function does not return */ -#define PNG_DEPSTRUCT /* Access to this struct member is deprecated */ #endif /* !PNGCRUSH_H */ |