summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pngcrush.c215
-rw-r--r--pngcrush.h25
2 files changed, 185 insertions, 55 deletions
diff --git a/pngcrush.c b/pngcrush.c
index 25958588e..453c1f8ec 100644
--- a/pngcrush.c
+++ b/pngcrush.c
@@ -80,7 +80,7 @@
*
*/
-#define PNGCRUSH_VERSION "1.7.50"
+#define PNGCRUSH_VERSION "1.7.51"
/* Experimental: define these if you wish, but, good luck.
#define PNGCRUSH_COUNT_COLORS
@@ -88,6 +88,11 @@
*/
#define PNGCRUSH_LARGE
+#define PNGCRUSH_ROWBYTES(pixel_bits, width) \
+ ((pixel_bits) >= 8 ? \
+ ((png_size_t)(width) * (((png_size_t)(pixel_bits)) >> 3)) : \
+ (( ((png_size_t)(width) * ((png_size_t)(pixel_bits))) + 7) >> 3) )
+
/*
* NOTICES
*
@@ -162,7 +167,7 @@
* cp $1 temp-$$.png
* for w in 512 1 2 4 8 16 32
* do
- * pngcrush -ow -w $w -brute temp-$$.png
+ * pngcrush -ow -w $w -brute temp-$$.png
* done
* mv temp-$$.png $2
*
@@ -191,7 +196,8 @@
*
* 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.
+ * course involves a lot more trial compressions, but it will catch
+ * those instances where a smaller file will result.
*
* 2. Check for the possiblity of using the tRNS chunk instead of
* the full alpha channel. If all of the transparent pixels are
@@ -272,10 +278,23 @@
Change log:
+Version 1.7.51 (built with libpng-1.6.0 and zlib-1.2.7)
+ Added "-noreduce" option, in preparation for "-reduce" becoming the
+ default behaviour in version 1.8.0. This turns off lossless bit depth,
+ color type and palette reduction, and opaque alpha channel removal.
+ Zero out the high byte of transparent color for color-type 0 and 2,
+ when reducing from 16 bits to 8.
+ Undefined a bunch of stuff in pngcrush.h that we do not use, saves about
+ 100 kbytes of executable file size in addition to about 50k saved by
+ undefining the simplified API.
+ Fixed double-underscore typo in an #ifdef in png.c
+ If "-reduce" is on and the background index is larger than the reduced
+ palette_length+1, reduce it to the palette_length+1.
+
Version 1.7.50 (built with libpng-1.6.0 and zlib-1.2.7)
Removed completed items from the "To do" list.
Ignore the argument of the "plte_len" argument and just set the
- "reduce_palette" flag.
+ "reduce_palette" flag.
Version 1.7.49 (built with libpng-1.5.14 and zlib-1.2.7)
Use png_set_benign_errors() to allow certain errors in the input file
@@ -296,7 +315,7 @@ Version 1.7.48 (built with libpng-1.5.14 and zlib-1.2.7)
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 200 in the pngcrush.c source).
+ about line 200 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)
@@ -531,7 +550,7 @@ Version 1.7.7 (built with libpng-1.4.0 and zlib-1.2.3.4)
Version 1.7.6 (built with libpng-1.4.0rc02 and zlib-1.2.3.2)
Change some "#if defined(X)" to "#ifdef X" according to libpng coding style.
Added some defines to suppress pedantic warnings from libpng-1.2.41beta15
- and later. A warning about deprecated access to png_ptr->zstream is
+ and later. A warning about deprecated access to png_ptr->zstream is
otherwise unavoidable. When building the embedded libpng, a warning
about png_default_error() returning is also otherwise unavoidable.
Write premultiplied alpha if output extension is .ppng and
@@ -833,7 +852,7 @@ Version 1.4.5 (built with libpng-1.0.7rc2 and cexcept-1.0.0)
or grayscale when fewer than 257 RGBA combinations are present,
and no color is present that requires 16-bit precision. For now,
it only reports the frequencies.
-
+
Added "-fix" option, for fixing bad CRCs and other correctable
conditions.
@@ -924,7 +943,7 @@ Version 1.3.3 (built with libpng-1.0.5m)
arithmetic is not enabled.
Version 1.3.2 (built with libpng-1.0.5k)
-
+
Renamed "dirname" to "directory_name" to avoid conflict with "dirname"
that appears in string.h on some platforms.
@@ -1007,7 +1026,7 @@ Version 1.1.4: added ability to restrict brute_force to one or more filter
#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
*/
@@ -1249,7 +1268,7 @@ png_uint_32 pngcrush_crc;
#if defined(__DJGPP__) && ((__DJGPP__ == 2) && (__DJGPP_MINOR__ == 0))
# include <libc/dosio.h> /* for _USE_LFN, djgpp 2.0 only */
-#endif
+#endif
#if ( defined(_Windows) || defined(_WINDOWS) || defined(WIN32) || \
defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) || \
@@ -1360,6 +1379,8 @@ static int found_cHRM = 0;
#endif
static int premultiply = 0;
+static int interlace_method = 0;
+png_alloc_size_t max_bytes;
/* 0: not premultipled
* 1: premultiplied input (input has .ppng suffix)
@@ -1437,7 +1458,7 @@ static int trial;
static int last_trial = 0;
static png_uint_32 pngcrush_write_byte_count;
static png_uint_32 pngcrush_best_byte_count=0xffffffff;
-
+
static int verbose = 1;
static int fix = 0;
static int bail = 0; /* if 0, bail out of trials early */
@@ -1517,6 +1538,7 @@ 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_byte bkgd_index = 0;
static png_colorp palette;
static int num_palette;
@@ -1926,7 +1948,7 @@ static void png_cexcept_error(png_structp png_ptr, png_const_charp err_msg)
* a benign error, "Too many IDATs found".
*/
#if PNG_LIBPNG_VER < 10400
-# ifdef PNGCRUSH_H
+# ifdef PNGCRUSH_H
if (!strcmp(err_msg, "Too many IDAT's found")) {
# ifdef PNG_CONSOLE_IO_SUPPORTED
fprintf(stderr, "\nIn %s, correcting ", inname);
@@ -2380,7 +2402,7 @@ static void pngcrush_flush(png_structp png_ptr)
void pngcrush_examine_pixels_fn(png_structp png_ptr, png_row_infop
row_info, png_bytep data)
{
-
+
if (blacken == 1 || make_gray == 1 || make_opaque == 1)
{
@@ -2403,13 +2425,13 @@ void pngcrush_examine_pixels_fn(png_structp png_ptr, png_row_infop
*/
int i;
-
+
if (row_info->color_type < 4)
{
blacken = 3; /* It doesn't have an alpha channel */
make_opaque = 3;
}
-
+
if (row_info->color_type == 0 || row_info->color_type == 4)
make_gray = 3; /* It's already gray! */
@@ -2431,11 +2453,11 @@ void pngcrush_examine_pixels_fn(png_structp png_ptr, png_row_infop
{
make_gray = 2;
}
-
+
i-=3;
}
}
-
+
else /* bit depth == 16 */
{
for ( ; i > 0 ; )
@@ -2469,7 +2491,7 @@ void pngcrush_examine_pixels_fn(png_structp png_ptr, png_row_infop
i-=2;
}
}
-
+
else /* bit depth == 16 */
{
for ( ; i > 0 ; )
@@ -2487,7 +2509,7 @@ void pngcrush_examine_pixels_fn(png_structp png_ptr, png_row_infop
}
}
}
-
+
/* color_type == 6, RGBA */
else if (row_info->color_type == 6 && (blacken == 1 || make_gray == 1 ||
make_opaque == 1))
@@ -2511,11 +2533,11 @@ void pngcrush_examine_pixels_fn(png_structp png_ptr, png_row_infop
{
make_opaque = 2;
}
-
+
i-=4;
}
}
-
+
else /* bit depth == 16 */
{
for ( ; i > 0 ; )
@@ -2596,14 +2618,14 @@ void pngcrush_examine_pixels_fn(png_structp png_ptr, png_row_infop
void pngcrush_transform_pixels_fn(png_structp png_ptr, png_row_infop row_info,
png_bytep data)
{
-
+
int i;
if (blacken == 2)
{
/* 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)
@@ -2617,7 +2639,7 @@ void pngcrush_transform_pixels_fn(png_structp png_ptr, png_row_infop row_info,
i-=2;
}
}
-
+
else /* bit depth == 16 */
{
for ( ; i > 0 ; )
@@ -2632,7 +2654,7 @@ void pngcrush_transform_pixels_fn(png_structp png_ptr, png_row_infop row_info,
}
}
}
-
+
else /* color_type == 6, RGBA */
{
if (row_info->bit_depth == 8)
@@ -2649,7 +2671,7 @@ void pngcrush_transform_pixels_fn(png_structp png_ptr, png_row_infop row_info,
i-=4;
}
}
-
+
else /* bit depth == 16 */
{
for ( ; i > 0 ; )
@@ -2873,7 +2895,7 @@ int main(int argc, char *argv[])
else if (!strncmp(argv[i], "-bail", 5))
bail=0;
-
+
else if (!strncmp(argv[i], "-nobail", 7))
bail=1;
@@ -2885,6 +2907,7 @@ int main(int argc, char *argv[])
bkgd_red = (png_uint_16) atoi(argv[++i]);
bkgd_green = (png_uint_16) atoi(argv[++i]);
bkgd_blue = (png_uint_16) atoi(argv[++i]);
+ bkgd_index = 0;
}
else if (!strncmp(argv[i], "-blacken", 8))
@@ -3183,6 +3206,14 @@ int main(int argc, char *argv[])
no_limits++;
}
+ else if (!strncmp(argv[i], "-noreduce", 9))
+ {
+ make_opaque = 0;
+ make_gray = 0;
+ make_8_bit = 0;
+ reduce_palette = 0;
+ }
+
else if (!strncmp(argv[i], "-nosave", 2))
{
/* no save; I just use this for testing decode speed */
@@ -3769,7 +3800,7 @@ int main(int argc, char *argv[])
#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,
@@ -3783,7 +3814,7 @@ int main(int argc, char *argv[])
# 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",
@@ -3815,7 +3846,7 @@ int main(int argc, char *argv[])
if (verbose > 0)
{
-
+
fprintf(STDERR, " Recompressing %s\n", inname);
fprintf(STDERR,
" Total length of data found in critical chunks = %8lu\n",
@@ -4567,7 +4598,7 @@ int main(int argc, char *argv[])
* - unknown chunks
*/
{
- int interlace_method, compression_method,
+ int compression_method,
filter_method;
P1( "Transferring info struct\n");
@@ -4772,7 +4803,7 @@ int main(int argc, char *argv[])
if (nosave == 0 && last_trial == 1)
png_permit_mng_features(write_ptr,
PNG_FLAG_MNG_FILTER_64);
-
+
}
} else
filter_method = 0;
@@ -4843,6 +4874,7 @@ int main(int argc, char *argv[])
backgrnd->green = bkgd_green;
backgrnd->blue = bkgd_blue;
backgrnd->gray = backgrnd->green;
+ backgrnd->index = bkgd_index;
png_set_bKGD(write_ptr, write_info_ptr,
backgrnd);
}
@@ -5013,11 +5045,13 @@ int main(int argc, char *argv[])
fprintf(STDERR, " Ignoring sRGB request; "
# ifdef PNG_FIXED_POINT_SUPPORTED
"gamma=(%lu/100000)"
+ " is not approx. 0.455\n",
+ (unsigned long)file_gamma);
# else
"gamma=%f"
-# endif
" is not approx. 0.455\n",
- (unsigned long)file_gamma);
+ file_gamma);
+# endif
}
}
#endif /* PNG_gAMA_SUPPORTED */
@@ -5149,7 +5183,7 @@ int main(int argc, char *argv[])
res_y, unit_type);
if (verbose > 0 && last_trial)
fprintf(STDERR, " Added pHYs %lu %lu 1 chunk\n",
- (unsigned long)res_x,
+ (unsigned long)res_x,
(unsigned long)res_y);
}
}
@@ -5214,11 +5248,25 @@ int main(int argc, char *argv[])
}
num_trans = last_nonmax + 1;
}
+ else
+ {
+ /* color type is 0 or 2 */
+ if (input_bit_depth == 16 &&
+ output_bit_depth == 8)
+ {
+ /* zero out the high byte */
+ trans_values->red &= 0x00ff;
+ trans_values->green &= 0x00ff;
+ trans_values->blue &= 0x00ff;
+ trans_values->gray &= 0x00ff;
+ }
+
+ }
if (verbose > 1)
fprintf(STDERR,
" png_set_tRNS, num_trans=%d\n",
num_trans);
- if (output_color_type != 3 || num_trans)
+ if (output_color_type < 3 || num_trans)
png_set_tRNS(write_ptr, write_info_ptr,
trans, num_trans,
trans_values);
@@ -5770,10 +5818,54 @@ int main(int argc, char *argv[])
if (output_color_type == 6)
channels = 4;
- required_window =
- (png_uint_32) (height *
- ((width * channels * bit_depth +
- 15) >> 3) + 262);
+ /* This method was copied from libpng to find maximum
+ * data size. Only return sizes up to the maximum of
+ * a png_uint_32, by limiting the width and height used
+ * to 15 bits.
+ */
+ png_uint_32 rowbytes;
+ png_uint_32 h = height;
+
+ rowbytes = png_get_rowbytes(read_ptr, read_info_ptr);
+ if (rowbytes < 16384 && h < 16384)
+ {
+ if (rowbytes * h < 16384)
+ {
+ if (interlace_method)
+ {
+ /* Interlacing makes the image larger because of
+ * the replication of both the filter byte and the
+ * padding to a byte boundary.
+ */
+ png_uint_32 w = width;
+ unsigned int pd = channels * output_bit_depth;
+ png_alloc_size_t cb_base;
+ int interlace_pass;
+
+ for (cb_base=0, interlace_pass=0;
+ interlace_pass<=6; ++interlace_pass)
+ {
+ png_uint_32 pw = PNG_PASS_COLS(w, interlace_pass);
+
+ if (pw > 0)
+ cb_base += (PNGCRUSH_ROWBYTES(pd, pw)+1) *
+ PNG_PASS_ROWS(h, interlace_pass);
+ }
+
+ max_bytes = cb_base;
+ }
+
+ else
+ max_bytes = (rowbytes+1) * h;
+ }
+ else
+ max_bytes = 0x3fffffffU;
+ }
+
+ else
+ max_bytes = 0x3fffffffU;
+
+ required_window = (png_uint_32) (max_bytes + 262);
zbuf_size =
png_get_compression_buffer_size(write_ptr);
@@ -6011,9 +6103,19 @@ int main(int argc, char *argv[])
png_color_16p bkgd;
if (png_get_bKGD(read_ptr, read_info_ptr, &bkgd))
{
- P1("bKGD index = %d\n", bkgd->index);
+ bkgd_index = bkgd->index;
+ P1("bKGD index = %d\n", bkgd_index);
+#if 1
+ if (bkgd_index > palette_length+1)
+ {
+ bkgd_index = palette_length+1;
+ have_bkgd = 1;
+ fprintf(STDERR,
+ " New bKGD index = %d\n", bkgd_index);
+ }
+#endif
if (bkgd->index > palette_length)
- palette_length = (int) bkgd->index;
+ palette_length = (int) bkgd_index+1;
P1("Total palette length = %d\n", palette_length);
}
}
@@ -6193,7 +6295,7 @@ int main(int argc, char *argv[])
text_compression[ntext];
png_set_text(write_ptr, write_end_info_ptr,
added_text, 1);
-
+
if (verbose > 0 && last_trial)
{
if (added_text[0].compression < 0)
@@ -6379,9 +6481,9 @@ int main(int argc, char *argv[])
(unsigned long)idat_length[trial]);
fflush(STDERR);
}
-
+
} /* end of trial-loop */
-
+
P1("\n\nFINISHED MAIN LOOP OVER %d METHODS\n\n\n", MAX_METHODS);
/* ////////////////////////////////////////////////////////////////////
@@ -6400,7 +6502,7 @@ int main(int argc, char *argv[])
FCLOSE(fpout);
setfiletype(outname);
}
-
+
if (last_trial && nosave == 0 && overwrite != 0)
{
/* rename the new file , outname = inname */
@@ -6455,7 +6557,7 @@ int main(int argc, char *argv[])
{
fprintf(STDERR,
" Best pngcrush method = %d "
- "(ws %d fm %d zl %d zs %d) = %8lu\n for %s\n", best,
+ "(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);
}
@@ -7238,6 +7340,11 @@ struct options_help pngcrush_options[] = {
{2, ""},
#endif
+ {0, " -n (no save; doesn't do compression or write output PNG)"},
+ {2, ""},
+ {2, " Useful in conjunction with -v option to get info."},
+ {2, ""},
+
{0, " -newtimestamp (Reset file modification time [default])"},
{2, ""},
@@ -7259,9 +7366,12 @@ struct options_help pngcrush_options[] = {
{2, " Instead, the user limits are inherited from libpng."},
{2, ""},
+ {0, " -noreduce (turns off \"-reduce\" operations)"},
+ {2, ""},
+
{0, " -oldtimestamp (Do not reset file modification time)"},
{2, ""},
-
+
{0, " -ow (Overwrite)"},
{2, ""},
{2, " Overwrite the input file. The input file is "},
@@ -7269,11 +7379,6 @@ struct options_help pngcrush_options[] = {
{2, " is renamed to the input file after recompression"},
{2, " and therefore they must reside on the same filesystem"},
{2, ""},
-
- {0, " -n (no save; doesn't do compression or write output PNG)"},
- {2, ""},
- {2, " Useful in conjunction with -v option to get info."},
- {2, ""},
{0, " -plte_len n (obsolete, n is ignored, sets automatic reduction)"},
{2, ""},
@@ -7283,7 +7388,9 @@ struct options_help pngcrush_options[] = {
{0, " -reduce (do lossless color-type or bit-depth reduction)"},
{2, ""},
- {2, " (if possible)"},
+ {2, " (if possible). Also reduces palette length if"},
+ {2, " if possible. Currently only attempts to reduce the"},
+ {2, " bit depth from 16 to 8"},
{2, ""},
{0, " -rem chunkname (or \"alla\" or \"allb\")"},
diff --git a/pngcrush.h b/pngcrush.h
index 1cce42e5d..ea3cd11ca 100644
--- a/pngcrush.h
+++ b/pngcrush.h
@@ -5,12 +5,35 @@
* license (see LICENSE, in pngcrush.c).
*/
-/* Special defines for pngcrush version 1.7.50 */
+/* Special defines for pngcrush version 1.7.51 */
#ifndef PNGCRUSH_H
#define PNGCRUSH_H
+/* Do not build stuff we will not use */
+#undef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED
+#undef PNG_EASY_ACCESS_SUPPORTED
+#undef PNG_FIXED_POINT_SUPPORTED
+#undef PNG_INCH_CONVERSIONS_SUPPORTED
#undef PNG_PROGRESSIVE_READ_SUPPORTED
+#undef PNG_READ_ALPHA_MODE_SUPPORTED
+#undef PNG_READ_BGR_SUPPORTED
+#undef PNG_READ_COMPOSITE_NODIV_SUPPORTED
+#undef PNG_READ_GAMMA_SUPPORTED
+#undef PNG_READ_STRIP_16_TO_8_SUPPORTED
+#undef PNG_READ_SWAP_ALPHA_SUPPORTED
+#undef PNG_READ_SWAP_SUPPORTED
+#undef PNG_READ_INVERT_ALPHA_SUPPORTED
+#undef PNG_READ_INVERT_SUPPORTED
+#undef PNG_READ_QUANTIZE_SUPPORTED
+#undef PNG_TIME_RFC1123_SUPPORTED
+#undef PNG_WRITE_BGR_SUPPORTED
+#undef PNG_WRITE_GET_PALETTE_MAX_SUPPORTED
+#undef PNG_WRITE_INVERT_ALPHA_SUPPORTED
+#undef PNG_WRITE_INVERT_SUPPORTED
+#undef PNG_WRITE_SWAP_ALPHA_SUPPORTED
+#undef PNG_WRITE_SWAP_SUPPORTED
+#undef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
#if PNG_LIBPNG_VER >= 10600
# undef PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED