[libpng16] 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.
This commit is contained in:
John Bowler 2012-09-01 11:46:14 -05:00 committed by Glenn Randers-Pehrson
parent 97a77a6f7b
commit d099973c4f
4 changed files with 127 additions and 32 deletions

View File

@ -488,6 +488,12 @@ Version 1.6.0beta29 [September 1, 2012]
Added contrib/examples/* to the *.zip and *.7z distributions. Added contrib/examples/* to the *.zip and *.7z distributions.
Updated simplified API synopses and description of the png_image structure Updated simplified API synopses and description of the png_image structure
in the manual. 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 Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit (subscription required; visit

View File

@ -4240,6 +4240,12 @@ Version 1.6.0beta29 [September 1, 2012]
Added contrib/examples/* to the *.zip and *.7z distributions. Added contrib/examples/* to the *.zip and *.7z distributions.
Updated simplified API synopses and description of the png_image structure Updated simplified API synopses and description of the png_image structure
in the manual. 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 Send comments/corrections/commendations to png-mng-implement at lists.sf.net
(subscription required; visit (subscription required; visit

View File

@ -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, static void PNGCBAPI
volatile png_fixed_point gamma, chunk_insert * volatile insert) 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_infop info_ptr = NULL;
volatile png_bytep row = 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); png_write_info(png_ptr, info_ptr);
/* Restrict the filters */ /* 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); int passes = png_set_interlace_handling(png_ptr);
@ -604,7 +629,10 @@ load_file(png_const_charp name, png_bytepp result)
if (total > 0) 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) if (data != NULL)
{ {
@ -729,12 +757,13 @@ insert_iCCP(png_structp png_ptr, png_infop info_ptr, int nparams,
case '<': case '<':
{ {
png_size_t filelen = load_file(params[1]+1, &profile); 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", fprintf(stderr, "%s: file too long (%lu) for an ICC profile\n",
params[1]+1, (unsigned long)filelen); params[1]+1, (unsigned long)filelen);
exit(1); exit(1);
} }
proflen = (png_uint_32)filelen; proflen = (png_uint_32)filelen;
} }
break; break;
@ -771,9 +800,14 @@ insert_iCCP(png_structp png_ptr, png_infop info_ptr, int nparams,
if (proflen & 3) if (proflen & 3)
{ {
fprintf(stderr, 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]); 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) if (profile != NULL && proflen > 3)
@ -1067,6 +1101,7 @@ main(int argc, char **argv)
const char *file_name = NULL; const char *file_name = NULL;
int color_type = 8; /* invalid */ int color_type = 8; /* invalid */
int bit_depth = 32; /* invalid */ int bit_depth = 32; /* invalid */
unsigned int filters = PNG_ALL_FILTERS;
png_fixed_point gamma = 0; /* not set */ png_fixed_point gamma = 0; /* not set */
chunk_insert *head_insert = NULL; chunk_insert *head_insert = NULL;
chunk_insert **insert_ptr = &head_insert; chunk_insert **insert_ptr = &head_insert;
@ -1093,6 +1128,12 @@ main(int argc, char **argv)
continue; continue;
} }
if (strcmp(arg, "--nofilters") == 0)
{
filters = PNG_FILTER_NONE;
continue;
}
if (argc >= 3 && strcmp(arg, "--insert") == 0) if (argc >= 3 && strcmp(arg, "--insert") == 0)
{ {
png_const_charp what = *++argv; png_const_charp what = *++argv;
@ -1209,8 +1250,30 @@ main(int argc, char **argv)
exit(1); 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) if (ret != 0 && file_name != NULL)
remove(file_name); remove(file_name);

View File

@ -95,6 +95,7 @@ static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present";
static int verbose = 0; static int verbose = 0;
static int strict = 0; static int strict = 0;
static int relaxed = 0;
static int unsupported_chunks = 0; /* chunk unsupported by libpng in input */ static int unsupported_chunks = 0; /* chunk unsupported by libpng in input */
static int error_count = 0; /* count calls to png_error */ static int error_count = 0; /* count calls to png_error */
static int warning_count = 0; /* count calls to png_warning */ 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); pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING);
#endif #endif
} }
#endif /* !PNG_STDIO_SUPPORTED */
/* This function is called when there is a warning, but the library thinks /* 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 * 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) pngtest_warning(png_structp png_ptr, png_const_charp message)
{ {
PNG_CONST char *name = "UNKNOWN (ERROR!)"; PNG_CONST char *name = "UNKNOWN (ERROR!)";
char *test; PNG_CONST char **test= (PNG_CONST char **)png_get_error_ptr(png_ptr);
test = png_get_error_ptr(png_ptr);
++warning_count; ++warning_count;
if (test == NULL) if (test == NULL || *test == NULL)
fprintf(STDERR, "%s: libpng warning: %s\n", name, message); fprintf(STDERR, "%s: libpng warning: %s\n", name, message);
else 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 /* 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. * actually OK in this case.
*/ */
} }
#endif /* !PNG_STDIO_SUPPORTED */
/* END of code to validate stdio-free compilation */ /* END of code to validate stdio-free compilation */
/* START of code to validate memory allocation and deallocation */ /* 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 fpin;
static png_FILE_p fpout; /* "static" prevents setjmp corruption */ static png_FILE_p fpout; /* "static" prevents setjmp corruption */
static PNG_CONST char *fp_name;
png_structp read_ptr; png_structp read_ptr;
png_infop read_info_ptr, end_info_ptr; png_infop read_info_ptr, end_info_ptr;
#ifdef PNG_WRITE_SUPPORTED #ifdef PNG_WRITE_SUPPORTED
@ -817,6 +819,7 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
int bit_depth, color_type; int bit_depth, color_type;
row_buf = NULL; row_buf = NULL;
fp_name = inname;
if ((fpin = fopen(inname, "rb")) == NULL) if ((fpin = fopen(inname, "rb")) == NULL)
{ {
@ -840,10 +843,7 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
read_ptr = read_ptr =
png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
#endif #endif
#ifndef PNG_STDIO_SUPPORTED png_set_error_fn(read_ptr, &fp_name, pngtest_error, pngtest_warning);
png_set_error_fn(read_ptr, (png_voidp)inname, pngtest_error,
pngtest_warning);
#endif
#ifdef PNG_WRITE_SUPPORTED #ifdef PNG_WRITE_SUPPORTED
#if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG #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 = write_ptr =
png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
#endif #endif
#ifndef PNG_STDIO_SUPPORTED png_set_error_fn(write_ptr, &fp_name, pngtest_error, pngtest_warning);
png_set_error_fn(write_ptr, (png_voidp)inname, pngtest_error,
pngtest_warning);
#endif
#endif #endif
pngtest_debug("Allocating read_info, write_info and end_info structures"); pngtest_debug("Allocating read_info, write_info and end_info structures");
read_info_ptr = png_create_info_struct(read_ptr); 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); png_set_benign_errors(write_ptr, 0);
#endif #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"); pngtest_debug("Initializing input and output streams");
@ -939,14 +949,6 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
# endif # endif
#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) if (status_dots_requested == 1)
{ {
#ifdef PNG_WRITE_SUPPORTED #ifdef PNG_WRITE_SUPPORTED
@ -1451,6 +1453,14 @@ test_one_file(PNG_CONST char *inname, PNG_CONST char *outname)
#endif #endif
#ifdef PNG_WRITE_SUPPORTED #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 /* 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 * 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 * 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; verbose = 1;
inname = argv[2]; inname = argv[2];
strict++; strict++;
relaxed = 0;
}
else if (strcmp(argv[1], "--relaxed") == 0)
{
status_dots_requested = 0;
verbose = 1;
inname = argv[2];
strict = 0;
relaxed++;
} }
else else