diff --git a/ANNOUNCE b/ANNOUNCE index 0c28a75dc..010f131a3 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -488,6 +488,12 @@ Version 1.6.0beta29 [September 1, 2012] Added contrib/examples/* to the *.zip and *.7z distributions. Updated simplified API synopses and description of the png_image structure in the manual. + Made makepng and pngtest produce identical PNGs, add "--relaxed" option + to pngtest. The "--relaxed" option turns off the benign errors that are + enabled by default in pre-RC builds. makepng can now write ICC profiles + where the length has not been extended to a multiple of 4, and pngtest + now intercepts all libpng errors, allowing the previously-introduced + "--strict test" on no warnings to actually work. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/CHANGES b/CHANGES index 0574d8f70..44603cef4 100644 --- a/CHANGES +++ b/CHANGES @@ -4240,6 +4240,12 @@ Version 1.6.0beta29 [September 1, 2012] Added contrib/examples/* to the *.zip and *.7z distributions. Updated simplified API synopses and description of the png_image structure in the manual. + Made makepng and pngtest produce identical PNGs, add "--relaxed" option + to pngtest. The "--relaxed" option turns off the benign errors that are + enabled by default in pre-RC builds. makepng can now write ICC profiles + where the length has not been extended to a multiple of 4, and pngtest + now intercepts all libpng errors, allowing the previously-introduced + "--strict test" on no warnings to actually work. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/contrib/libtests/makepng.c b/contrib/libtests/makepng.c index 5fdaa67d9..969cbcf95 100644 --- a/contrib/libtests/makepng.c +++ b/contrib/libtests/makepng.c @@ -392,11 +392,36 @@ generate_row(png_bytep row, size_t rowbytes, unsigned int y, int color_type, } } -static int /* 0 on success, else an error code */ -write_png(FILE *fp, int color_type, int bit_depth, - volatile png_fixed_point gamma, chunk_insert * volatile insert) + +static void PNGCBAPI +makepng_warning(png_structp png_ptr, png_const_charp message) { - png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,0,0,0); + const char **ep = png_get_error_ptr(png_ptr); + const char *name; + + if (ep != NULL && *ep != NULL) + name = *ep; + + else + name = "makepng"; + + fprintf(stderr, "%s: warning: %s\n", name, message); +} + +static void PNGCBAPI +makepng_error(png_structp png_ptr, png_const_charp message) +{ + makepng_warning(png_ptr, message); + png_longjmp(png_ptr, 1); +} + +static int /* 0 on success, else an error code */ +write_png(const char **name, FILE *fp, int color_type, int bit_depth, + volatile png_fixed_point gamma, chunk_insert * volatile insert, + unsigned int filters) +{ + png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, + name, makepng_error, makepng_warning); volatile png_infop info_ptr = NULL; volatile png_bytep row = NULL; @@ -517,7 +542,7 @@ write_png(FILE *fp, int color_type, int bit_depth, png_write_info(png_ptr, info_ptr); /* Restrict the filters */ - png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, PNG_NO_FILTERS); + png_set_filter(png_ptr, PNG_FILTER_TYPE_BASE, filters); { int passes = png_set_interlace_handling(png_ptr); @@ -604,7 +629,10 @@ load_file(png_const_charp name, png_bytepp result) if (total > 0) { - png_bytep data = malloc(total); + /* Round up to a multiple of 4 here to allow an iCCP profile + * to be padded to a 4x boundary. + */ + png_bytep data = malloc((total+3)&~3); if (data != NULL) { @@ -729,12 +757,13 @@ insert_iCCP(png_structp png_ptr, png_infop info_ptr, int nparams, case '<': { png_size_t filelen = load_file(params[1]+1, &profile); - if (filelen > 0xffffffff) /* Maximum profile length */ + if (filelen > 0xfffffffc) /* Maximum profile length */ { fprintf(stderr, "%s: file too long (%lu) for an ICC profile\n", params[1]+1, (unsigned long)filelen); exit(1); } + proflen = (png_uint_32)filelen; } break; @@ -771,9 +800,14 @@ insert_iCCP(png_structp png_ptr, png_infop info_ptr, int nparams, if (proflen & 3) { fprintf(stderr, - "--insert iCCP %s: profile length must be a multiple of 4\n", + "makepng: --insert iCCP %s: profile length made a multiple of 4\n", params[1]); - result = 0; /* Cannot fix this! */ + + /* load_file allocates extra space for this padding, the ICC spec requires + * padding with zero bytes. + */ + while (proflen & 3) + profile[proflen++] = 0; } if (profile != NULL && proflen > 3) @@ -1067,6 +1101,7 @@ main(int argc, char **argv) const char *file_name = NULL; int color_type = 8; /* invalid */ int bit_depth = 32; /* invalid */ + unsigned int filters = PNG_ALL_FILTERS; png_fixed_point gamma = 0; /* not set */ chunk_insert *head_insert = NULL; chunk_insert **insert_ptr = &head_insert; @@ -1093,6 +1128,12 @@ main(int argc, char **argv) continue; } + if (strcmp(arg, "--nofilters") == 0) + { + filters = PNG_FILTER_NONE; + continue; + } + if (argc >= 3 && strcmp(arg, "--insert") == 0) { png_const_charp what = *++argv; @@ -1209,8 +1250,30 @@ main(int argc, char **argv) exit(1); } + /* Restrict the filters for more speed to those we know are used for the + * generated images. + */ + if (filters == PNG_ALL_FILTERS) { - int ret = write_png(fp, color_type, bit_depth, gamma, head_insert); + if ((color_type & PNG_COLOR_MASK_PALETTE) != 0 || bit_depth < 8) + filters = PNG_FILTER_NONE; + + else if (color_type & PNG_COLOR_MASK_COLOR) /* rgb */ + { + if (bit_depth == 8) + filters &= ~(PNG_FILTER_NONE | PNG_FILTER_AVG); + + else + filters = PNG_FILTER_SUB | PNG_FILTER_PAETH; + } + + else /* gray 8 or 16-bit */ + filters &= ~PNG_FILTER_NONE; + } + + { + int ret = write_png(&file_name, fp, color_type, bit_depth, gamma, + head_insert, filters); if (ret != 0 && file_name != NULL) remove(file_name); diff --git a/pngtest.c b/pngtest.c index b8e798669..502fc226b 100644 --- a/pngtest.c +++ b/pngtest.c @@ -95,6 +95,7 @@ static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present"; static int verbose = 0; static int strict = 0; +static int relaxed = 0; static int unsupported_chunks = 0; /* chunk unsupported by libpng in input */ static int error_count = 0; /* count calls to png_error */ static int warning_count = 0; /* count calls to png_warning */ @@ -395,6 +396,7 @@ pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING); #endif } +#endif /* !PNG_STDIO_SUPPORTED */ /* This function is called when there is a warning, but the library thinks * it can continue anyway. Replacement functions don't have to do anything @@ -405,16 +407,15 @@ static void PNGCBAPI pngtest_warning(png_structp png_ptr, png_const_charp message) { PNG_CONST char *name = "UNKNOWN (ERROR!)"; - char *test; - test = png_get_error_ptr(png_ptr); + PNG_CONST char **test= (PNG_CONST char **)png_get_error_ptr(png_ptr); ++warning_count; - if (test == NULL) + if (test == NULL || *test == NULL) fprintf(STDERR, "%s: libpng warning: %s\n", name, message); else - fprintf(STDERR, "%s: libpng warning: %s\n", test, message); + fprintf(STDERR, "%s: libpng warning: %s\n", *test, message); } /* This is the default error handling function. Note that replacements for @@ -432,7 +433,7 @@ pngtest_error(png_structp png_ptr, png_const_charp message) * actually OK in this case. */ } -#endif /* !PNG_STDIO_SUPPORTED */ + /* END of code to validate stdio-free compilation */ /* START of code to validate memory allocation and deallocation */ @@ -799,6 +800,7 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) { static png_FILE_p fpin; static png_FILE_p fpout; /* "static" prevents setjmp corruption */ + static PNG_CONST char *fp_name; png_structp read_ptr; png_infop read_info_ptr, end_info_ptr; #ifdef PNG_WRITE_SUPPORTED @@ -817,6 +819,7 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) int bit_depth, color_type; row_buf = NULL; + fp_name = inname; if ((fpin = fopen(inname, "rb")) == NULL) { @@ -840,10 +843,7 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) read_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); #endif -#ifndef PNG_STDIO_SUPPORTED - png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error, - pngtest_warning); -#endif + png_set_error_fn(read_ptr, &fp_name, pngtest_error, pngtest_warning); #ifdef PNG_WRITE_SUPPORTED #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG @@ -854,10 +854,7 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) write_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); #endif -#ifndef PNG_STDIO_SUPPORTED - png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error, - pngtest_warning); -#endif + png_set_error_fn(write_ptr, &fp_name, pngtest_error, pngtest_warning); #endif pngtest_debug("Allocating read_info, write_info and end_info structures"); read_info_ptr = png_create_info_struct(read_ptr); @@ -918,7 +915,20 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) png_set_benign_errors(write_ptr, 0); #endif - /* if strict is not set, then both are treated as warnings. */ + /* if strict is not set, then app warnings and errors are treated as + * warnings in release builds, but not in unstable builds; this can be + * changed with '--relaxed'. + */ + } + + else if (relaxed) + { + /* Allow application (pngtest) errors and warnings to pass */ + png_set_benign_errors(read_ptr, 1); + +#ifdef PNG_WRITE_SUPPORTED + png_set_benign_errors(write_ptr, 1); +#endif } pngtest_debug("Initializing input and output streams"); @@ -939,14 +949,6 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) # endif #endif -#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED - /* Normally one would use Z_DEFAULT_STRATEGY for text compression. - * This is here just to make pngtest replicate the results from libpng - * versions prior to 1.5.4, and to test this new API. - */ - png_set_text_compression_strategy(write_ptr, Z_FILTERED); -#endif - if (status_dots_requested == 1) { #ifdef PNG_WRITE_SUPPORTED @@ -1451,6 +1453,14 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) #endif #ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED + /* Normally one would use Z_DEFAULT_STRATEGY for text compression. + * This is here just to make pngtest replicate the results from libpng + * versions prior to 1.5.4, and to test this new API. + */ + png_set_text_compression_strategy(write_ptr, Z_FILTERED); +#endif + /* When the unknown vpAg/sTER chunks are written by pngtest the only way to * do it is to write them *before* calling png_write_end. When unknown * chunks are written by libpng, however, they are written just before IEND. * There seems to be no way round this, however vpAg/sTER are not expected @@ -1703,6 +1713,16 @@ main(int argc, char *argv[]) verbose = 1; inname = argv[2]; strict++; + relaxed = 0; + } + + else if (strcmp(argv[1], "--relaxed") == 0) + { + status_dots_requested = 0; + verbose = 1; + inname = argv[2]; + strict = 0; + relaxed++; } else