From 8d261262d974ab756d998d8315bd857354ecd826 Mon Sep 17 00:00:00 2001 From: John Bowler Date: Sat, 18 Jun 2011 13:37:11 -0500 Subject: [PATCH] [devel] Fixed pngvalid, simplified macros, added checking for 0 in sCAL. --- ANNOUNCE | 7 +++ CHANGES | 6 +++ example.c | 2 +- png.c | 92 +++++++++++++++++------------------ png.h | 9 ++-- pngpriv.h | 44 +++++++++++++++-- pngread.c | 13 +++-- pngrtran.c | 108 ++++++++++++++++++++++++----------------- pngrutil.c | 13 +++-- pngvalid.c | 51 +++++++++++++------ scripts/pnglibconf.dfa | 14 ++---- 11 files changed, 219 insertions(+), 140 deletions(-) diff --git a/ANNOUNCE b/ANNOUNCE index 69f6e63cb..cd609baa5 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -229,6 +229,13 @@ Version 1.5.4beta06 [June 18, 2011] Fixed new bug that was causing both strip_16 and scale_16 to be applied. Version 1.5.4beta07 [June 18, 2011] + Fixed pngvalid, simplified macros, added checking for 0 in sCAL. + The ACCURATE scale macro is no longer defined in 1.5 - call the + png_scale_16_to_8 API. Made sure that PNG_READ_16_TO_8 is still defined + if the png_strip_16_to_8 API is present. png_check_fp_number now + maintains some state so that positive, negative and zero values are + identified. sCAL uses these to be strictly spec conformant. + Send comments/corrections/commendations to png-mng-implement at lists.sf.net: (subscription required; visit diff --git a/CHANGES b/CHANGES index 80d161b9a..5071b5dbf 100644 --- a/CHANGES +++ b/CHANGES @@ -3492,6 +3492,12 @@ Version 1.5.4beta06 [June 18, 2011] Fixed new bug that was causing both strip_16 and scale_16 to be applied. Version 1.5.4beta07 [June 18, 2011] + Fixed pngvalid, simplified macros, added checking for 0 in sCAL. + The ACCURATE scale macro is no longer defined in 1.5 - call the + png_scale_16_to_8 API. Made sure that PNG_READ_16_TO_8 is still defined + if the png_strip_16_to_8 API is present. png_check_fp_number now + maintains some state so that positive, negative and zero values are + identified. sCAL uses these to be strictly spec conformant. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/example.c b/example.c index 74cc3bc2f..e7d2d2f3c 100644 --- a/example.c +++ b/example.c @@ -191,7 +191,7 @@ void read_png(FILE *fp, unsigned int sig_read) /* File is already open */ * Use accurate scaling if it's available, otherwise just chop off the * low byte. */ -#ifdef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED png_set_scale_16(png_ptr); #else png_set_strip_16(png_ptr); diff --git a/png.c b/png.c index f927655c0..f73a3610c 100644 --- a/png.c +++ b/png.c @@ -946,16 +946,9 @@ png_check_IHDR(png_structp png_ptr, /* Check an ASCII formated floating point value, see the more detailed * comments in pngpriv.h */ -/* The following is used internally to preserve the 'valid' flag */ +/* The following is used internally to preserve the sticky flags */ #define png_fp_add(state, flags) ((state) |= (flags)) -#define png_fp_set(state, value)\ - ((state) = (value) | ((state) & PNG_FP_WAS_VALID)) - -/* Internal type codes: bits above the base state! */ -#define PNG_FP_SIGN 0 /* [+-] */ -#define PNG_FP_DOT 4 /* . */ -#define PNG_FP_DIGIT 8 /* [0123456789] */ -#define PNG_FP_E 12 /* [Ee] */ +#define png_fp_set(state, value) ((state) = (value) | ((state) & PNG_FP_STICKY)) int /* PRIVATE */ png_check_fp_number(png_const_charp string, png_size_t size, int *statep, @@ -968,55 +961,55 @@ png_check_fp_number(png_const_charp string, png_size_t size, int *statep, { int type; /* First find the type of the next character */ + switch (string[i]) { - char ch = string[i]; - - if (ch >= 48 && ch <= 57) - type = PNG_FP_DIGIT; - - else switch (ch) - { - case 43: case 45: type = PNG_FP_SIGN; break; - case 46: type = PNG_FP_DOT; break; - case 69: case 101: type = PNG_FP_E; break; - default: goto PNG_FP_End; - } + case 43: type = PNG_FP_SAW_SIGN; break; + case 45: type = PNG_FP_SAW_SIGN + PNG_FP_NEGATIVE; break; + case 46: type = PNG_FP_SAW_DOT; break; + case 48: type = PNG_FP_SAW_DIGIT; break; + case 49: case 50: case 51: case 52: + case 53: case 54: case 55: case 56: + case 57: type = PNG_FP_SAW_DIGIT + PNG_FP_NONZERO; break; + case 69: + case 101: type = PNG_FP_SAW_E; break; + default: goto PNG_FP_End; } /* Now deal with this type according to the current * state, the type is arranged to not overlap the * bits of the PNG_FP_STATE. */ - switch ((state & PNG_FP_STATE) + type) + switch ((state & PNG_FP_STATE) + (type & PNG_FP_SAW_ANY)) { - case PNG_FP_INTEGER + PNG_FP_SIGN: + case PNG_FP_INTEGER + PNG_FP_SAW_SIGN: if (state & PNG_FP_SAW_ANY) goto PNG_FP_End; /* not a part of the number */ - png_fp_add(state, PNG_FP_SAW_SIGN); + png_fp_add(state, type); break; - case PNG_FP_INTEGER + PNG_FP_DOT: + case PNG_FP_INTEGER + PNG_FP_SAW_DOT: /* Ok as trailer, ok as lead of fraction. */ if (state & PNG_FP_SAW_DOT) /* two dots */ goto PNG_FP_End; else if (state & PNG_FP_SAW_DIGIT) /* trailing dot? */ - png_fp_add(state, PNG_FP_SAW_DOT); + png_fp_add(state, type); else - png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT); + png_fp_set(state, PNG_FP_FRACTION | type); break; - case PNG_FP_INTEGER + PNG_FP_DIGIT: + case PNG_FP_INTEGER + PNG_FP_SAW_DIGIT: if (state & PNG_FP_SAW_DOT) /* delayed fraction */ png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT); - png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID); + png_fp_add(state, type | PNG_FP_WAS_VALID); break; - case PNG_FP_INTEGER + PNG_FP_E: + + case PNG_FP_INTEGER + PNG_FP_SAW_E: if ((state & PNG_FP_SAW_DIGIT) == 0) goto PNG_FP_End; @@ -1024,17 +1017,17 @@ png_check_fp_number(png_const_charp string, png_size_t size, int *statep, break; - /* case PNG_FP_FRACTION + PNG_FP_SIGN: - goto PNG_FP_End; ** no sign in exponent */ + /* case PNG_FP_FRACTION + PNG_FP_SAW_SIGN: + goto PNG_FP_End; ** no sign in fraction */ - /* case PNG_FP_FRACTION + PNG_FP_DOT: + /* case PNG_FP_FRACTION + PNG_FP_SAW_DOT: goto PNG_FP_End; ** Because SAW_DOT is always set */ - case PNG_FP_FRACTION + PNG_FP_DIGIT: - png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID); + case PNG_FP_FRACTION + PNG_FP_SAW_DIGIT: + png_fp_add(state, type | PNG_FP_WAS_VALID); break; - case PNG_FP_FRACTION + PNG_FP_E: + case PNG_FP_FRACTION + PNG_FP_SAW_E: /* This is correct because the trailing '.' on an * integer is handled above - so we can only get here * with the sequence ".E" (with no preceding digits). @@ -1046,7 +1039,7 @@ png_check_fp_number(png_const_charp string, png_size_t size, int *statep, break; - case PNG_FP_EXPONENT + PNG_FP_SIGN: + case PNG_FP_EXPONENT + PNG_FP_SAW_SIGN: if (state & PNG_FP_SAW_ANY) goto PNG_FP_End; /* not a part of the number */ @@ -1054,15 +1047,15 @@ png_check_fp_number(png_const_charp string, png_size_t size, int *statep, break; - /* case PNG_FP_EXPONENT + PNG_FP_DOT: + /* case PNG_FP_EXPONENT + PNG_FP_SAW_DOT: goto PNG_FP_End; */ - case PNG_FP_EXPONENT + PNG_FP_DIGIT: - png_fp_add(state, PNG_FP_SAW_DIGIT + PNG_FP_WAS_VALID); + case PNG_FP_EXPONENT + PNG_FP_SAW_DIGIT: + png_fp_add(state, PNG_FP_SAW_DIGIT | PNG_FP_WAS_VALID); break; - /* case PNG_FP_EXPONEXT + PNG_FP_E: + /* case PNG_FP_EXPONEXT + PNG_FP_SAW_E: goto PNG_FP_End; */ default: goto PNG_FP_End; /* I.e. break 2 */ @@ -1090,8 +1083,11 @@ png_check_fp_string(png_const_charp string, png_size_t size) int state=0; png_size_t char_index=0; - return png_check_fp_number(string, size, &state, &char_index) && - (char_index == size || string[char_index] == 0); + if (png_check_fp_number(string, size, &state, &char_index) && + (char_index == size || string[char_index] == 0)) + return state /* must be non-zero - see above */; + + return 0; /* i.e. fail */ } #endif /* pCAL or sCAL */ @@ -1845,7 +1841,7 @@ png_8bit_l2[128] = #endif }; -static png_int_32 +PNG_STATIC png_int_32 png_log8bit(unsigned int x) { unsigned int lg2 = 0; @@ -1901,7 +1897,7 @@ png_log8bit(unsigned int x) * Zero (257): 0 * End (258): 23499 */ -static png_int_32 +PNG_STATIC png_int_32 png_log16bit(png_uint_32 x) { unsigned int lg2 = 0; @@ -1995,7 +1991,7 @@ for (i=11;i>=0;--i){ print i, " ", (1 - e(-(2^i)/65536*l(2))) * 2^(32-i), "\n"} 0 45425.85339951654943850496 #endif -static png_uint_32 +PNG_STATIC png_uint_32 png_exp(png_fixed_point x) { if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */ @@ -2043,7 +2039,7 @@ png_exp(png_fixed_point x) return 0; } -static png_byte +PNG_STATIC png_byte png_exp8bit(png_fixed_point lg2) { /* Get a 32-bit value: */ @@ -2057,7 +2053,7 @@ png_exp8bit(png_fixed_point lg2) return (png_byte)((x + 0x7fffffU) >> 24); } -static png_uint_16 +PNG_STATIC png_uint_16 png_exp16bit(png_fixed_point lg2) { /* Get a 32-bit value: */ diff --git a/png.h b/png.h index e5f2b8c7a..6d0109f15 100644 --- a/png.h +++ b/png.h @@ -1423,16 +1423,15 @@ PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structp png_ptr, # define PNG_BACKGROUND_GAMMA_UNIQUE 3 #endif -#ifdef PNG_READ_16_TO_8_SUPPORTED -# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* Scale a 16-bit depth file down to 8-bit, accurately. */ PNG_EXPORT(229, void, png_set_scale_16, (png_structp png_ptr)); -# endif +#endif -# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +#define PNG_READ_16_TO_8 SUPPORTED /* Name prior to 1.5.4 */ /* Strip the second byte of information from a 16-bit depth file. */ PNG_EXPORT(48, void, png_set_strip_16, (png_structp png_ptr)); -# endif #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED diff --git a/pngpriv.h b/pngpriv.h index 1d1903a5b..d770069ec 100644 --- a/pngpriv.h +++ b/pngpriv.h @@ -115,6 +115,13 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; # define PNG_ZBUF_SIZE 65536L #endif +/* PNG_STATIC is used to mark internal file scope functions if they need to be + * accessed for implementation tests (see the code in tests/?*). + */ +#ifndef PNG_STATIC +# define PNG_STATIC static +#endif + /* If warnings or errors are turned off the code is disabled or redirected here. * From 1.5.4 functions have been added to allow very limited formatting of * error and warning messages - this code will also be disabled here. @@ -281,7 +288,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; #define PNG_COMPOSE 0x0080 /* Was PNG_BACKGROUND */ #define PNG_BACKGROUND_EXPAND 0x0100 #define PNG_EXPAND_16 0x0200 /* Added to libpng 1.5.2 */ -#define PNG_16_TO_8 0x0400 +#define PNG_16_TO_8 0x0400 /* Becomes 'chop' in 1.5.4 */ #define PNG_RGBA 0x0800 #define PNG_EXPAND 0x1000 #define PNG_GAMMA 0x2000 @@ -298,7 +305,7 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; #define PNG_ENCODE_ALPHA 0x800000L /* Added to libpng-1.5.4 */ #define PNG_ADD_ALPHA 0x1000000L /* Added to libpng-1.2.7 */ #define PNG_EXPAND_tRNS 0x2000000L /* Added to libpng-1.2.9 */ -#define PNG_SCALE_16_TO_8 0x4000000L +#define PNG_SCALE_16_TO_8 0x4000000L /* Added to libpng-1.5.4 */ /* 0x8000000L unused */ /* 0x10000000L unused */ /* 0x20000000L unused */ @@ -819,7 +826,7 @@ PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, png_bytep row)); #endif -#ifdef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED PNG_EXTERN void png_do_scale_16_to_8 PNGARG((png_row_infop row_info, png_bytep row)); #endif @@ -1226,8 +1233,18 @@ PNG_EXTERN void png_ascii_from_fixed PNGARG((png_structp png_ptr, #define PNG_FP_SAW_DOT 16 /* Saw a dot in current state */ #define PNG_FP_SAW_E 32 /* Saw an E (or e) in current state */ #define PNG_FP_SAW_ANY 60 /* Saw any of the above 4 */ + +/* These three values don't affect the parser. They are set but not used. + */ #define PNG_FP_WAS_VALID 64 /* Preceding substring is a valid fp number */ -#define PNG_FP_INVALID 128 /* Available for callers as a distinct value */ +#define PNG_FP_NEGATIVE 128 /* A negative number, including "-0" */ +#define PNG_FP_NONZERO 256 /* A non-zero value */ +#define PNG_FP_STICKY 448 /* The above three flags */ + +/* This is available for the caller to store in 'state' if required. Do not + * call the parser after setting it (the parser sometimes clears it.) + */ +#define PNG_FP_INVALID 512 /* Available for callers as a distinct value */ /* Result codes for the parser (boolean - true meants ok, false means * not ok yet.) @@ -1235,6 +1252,20 @@ PNG_EXTERN void png_ascii_from_fixed PNGARG((png_structp png_ptr, #define PNG_FP_MAYBE 0 /* The number may be valid in the future */ #define PNG_FP_OK 1 /* The number is valid */ +/* Tests on the sticky non-zero and negative flags. To pass these checks + * the state must also indicate that the whole number is valid - this is + * achieved by testing PNG_FP_SAW_DIGIT (see the implementation for why this + * is equivalent to PNG_FP_OK above.) + */ +#define PNG_FP_NZ_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NEGATIVE | PNG_FP_NONZERO) + /* NZ_MASK: the string is valid and a non-zero negative value */ +#define PNG_FP_Z_MASK (PNG_FP_SAW_DIGIT | PNG_FP_NONZERO) + /* Z MASK: the string is valid and a non-zero value. */ + /* PNG_FP_SAW_DIGIT: the string is valid. */ +#define PNG_FP_IS_ZERO(state) (((state) & PNG_FP_Z_MASK) == PNG_FP_SAW_DIGIT) +#define PNG_FP_IS_POSITIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_Z_MASK) +#define PNG_FP_IS_NEGATIVE(state) (((state) & PNG_FP_NZ_MASK) == PNG_FP_NZ_MASK) + /* The actual parser. This can be called repeatedly, it updates * the index into the string and the state variable (which must * be initialzed to 0). It returns a result code, as above. There @@ -1254,7 +1285,10 @@ PNG_EXTERN int png_check_fp_number PNGARG((png_const_charp string, png_size_t size, int *statep, png_size_tp whereami)); /* This is the same but it checks a complete string and returns true - * only if it just contains a floating point number. + * only if it just contains a floating point number. As of 1.5.4 this + * function also returns the state at the end of parsing the number if + * it was valid (otherwise it returns 0.) This can be used for testing + * for negative or zero values using the sticky flag. */ PNG_EXTERN int png_check_fp_string PNGARG((png_const_charp string, png_size_t size)); diff --git a/pngread.c b/pngread.c index ba56032e0..552734699 100644 --- a/pngread.c +++ b/pngread.c @@ -1296,16 +1296,15 @@ png_read_png(png_structp png_ptr, png_infop info_ptr, */ png_set_scale_16(png_ptr); } - -# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED - else -# endif - #endif #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED - if (transforms & PNG_TRANSFORM_STRIP_16) - png_set_strip_16(png_ptr); + /* If both SCALE and STRIP are required pngrtran will effectively cancel the + * latter by doing SCALE first. This is ok and allows apps not to check for + * which is supported to get the right answer. + */ + if (transforms & PNG_TRANSFORM_STRIP_16) + png_set_strip_16(png_ptr); #endif #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED diff --git a/pngrtran.c b/pngrtran.c index e4ed0b996..41e2d523d 100644 --- a/pngrtran.c +++ b/pngrtran.c @@ -132,9 +132,11 @@ png_set_background(png_structp png_ptr, # endif /* FLOATING_POINT */ #endif /* READ_BACKGROUND */ -#ifdef PNG_READ_16_TO_8_SUPPORTED -/* Scale 16-bit depth files to 8-bit depth */ -# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +/* Scale 16-bit depth files to 8-bit depth. If both of these are set then the + * one that pngrtran does first (scale) happens. This is necessary to allow the + * TRANSFORM and API behavior to be somewhat consistent, and it's simpler. + */ +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED void PNGAPI png_set_scale_16(png_structp png_ptr) { @@ -144,13 +146,10 @@ png_set_scale_16(png_structp png_ptr) return; png_ptr->transformations |= PNG_SCALE_16_TO_8; -# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED - png_ptr->transformations &= ~PNG_16_TO_8; -# endif } -# endif +#endif -# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED /* Chop 16-bit depth files to 8-bit depth */ void PNGAPI png_set_strip_16(png_structp png_ptr) @@ -161,12 +160,8 @@ png_set_strip_16(png_structp png_ptr) return; png_ptr->transformations |= PNG_16_TO_8; -# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED - png_ptr->transformations &= ~PNG_SCALE_16_TO_8; -# endif } -# endif -#endif /* PNG_READ_16_TO_8_SUPPORTED */ +#endif #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED void PNGAPI @@ -1334,20 +1329,21 @@ png_init_read_transformations(png_structp png_ptr) * 6) PNG_GAMMA * 7) PNG_STRIP_ALPHA (if compose) * 8) PNG_ENCODE_ALPHA - * 9) PNG_16_TO_8 or PNG_SCALE_16_TO_8 (strip16/scale16) - * 10) PNG_QUANTIZE (converts to palette) - * 11) PNG_EXPAND_16 - * 12) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY - * 13) PNG_INVERT_MONO - * 14) PNG_SHIFT - * 15) PNG_PACK - * 16) PNG_BGR - * 17) PNG_PACKSWAP - * 18) PNG_FILLER (includes PNG_ADD_ALPHA) - * 19) PNG_INVERT_ALPHA - * 20) PNG_SWAP_ALPHA - * 21) PNG_SWAP_BYTES - * 22) PNG_USER_TRANSFORM [must be last] + * 9) PNG_SCALE_16_TO_8 + * 10) PNG_16_TO_8 + * 11) PNG_QUANTIZE (converts to palette) + * 12) PNG_EXPAND_16 + * 13) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY + * 14) PNG_INVERT_MONO + * 15) PNG_SHIFT + * 16) PNG_PACK + * 17) PNG_BGR + * 18) PNG_PACKSWAP + * 19) PNG_FILLER (includes PNG_ADD_ALPHA) + * 20) PNG_INVERT_ALPHA + * 21) PNG_SWAP_ALPHA + * 22) PNG_SWAP_BYTES + * 23) PNG_USER_TRANSFORM [must be last] */ #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED if ((png_ptr->transformations & PNG_STRIP_ALPHA) && @@ -1872,26 +1868,43 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr) info_ptr->gamma = png_ptr->gamma; #endif -#ifdef PNG_READ_16_TO_8_SUPPORTED -# ifdef PNG_READ_16BIT_SUPPORTED - if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) && - (info_ptr->bit_depth == 16)) - info_ptr->bit_depth = 8; -# else - - /* Force chopping 16-bit input down to 8 */ if (info_ptr->bit_depth == 16) { - if (!(png_ptr->transformations & PNG_16_TO_8)) -# if PNG_READ_STRIP_16_TO_8_SUPPORTED - png_ptr->transformations |=PNG_16_TO_8; -# else - png_ptr->transformations |=PNG_SCALE_16_TO_8; +# ifdef PNG_READ_16BIT_SUPPORTED +# ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + if (png_ptr->transformations & PNG_SCALE_16_TO_8) + info_ptr->bit_depth = 8; +# endif + +# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + if (png_ptr->transformations & PNG_16_TO_8) + info_ptr->bit_depth = 8; +# endif + +# else + /* No 16 bit support: force chopping 16-bit input down to 8, in this case + * the app program can chose if both APIs are available by setting the + * correct scaling to use. + */ +# ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + /* For compatibility with previous versions use the strip method by + * default. This code works because if PNG_SCALE_16_TO_8 is already + * set the code below will do that in preference to the chop. + */ + png_ptr->transformations |= PNG_16_TO_8; + info_ptr->bit_depth = 8; +# else + +# if PNG_READ_SCALE_16_TO_8_SUPPORTED + png_ptr->transformations |= PNG_SCALE_16_TO_8; + info_ptr->bit_depth = 8; +# else + + CONFIGURATION ERROR: you must enable at least one 16 to 8 method +# endif # endif - info_ptr->bit_depth = 8; +#endif /* !READ_16BIT_SUPPORTED */ } -# endif -#endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED if (png_ptr->transformations & PNG_GRAY_TO_RGB) @@ -2155,7 +2168,12 @@ png_do_read_transformations(png_structp png_ptr) if (png_ptr->transformations & PNG_SCALE_16_TO_8) png_do_scale_16_to_8(&(png_ptr->row_info), png_ptr->row_buf + 1); #endif + #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + /* There is no harm in doing both of these because only one has any effect, + * by putting the 'scale' option first if the app asks for scale (either by + * calling the API or in a TRANSFORM flag) this is what happens. + */ if (png_ptr->transformations & PNG_16_TO_8) png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1); #endif @@ -2562,8 +2580,8 @@ png_do_chop(png_row_infop row_info, png_bytep row) while (sp < ep) { - *dp++ = *sp++; - sp++; + *dp++ = *sp; + sp += 2; /* skip low byte */ } row_info->bit_depth = 8; diff --git a/pngrutil.c b/pngrutil.c index 2142a5e48..8510e99e1 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -2038,21 +2038,26 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) i = 1; state = 0; - if (png_ptr->chunkdata[1] == 45 /* negative width */ || - !png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) || + if (!png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) || i >= slength || png_ptr->chunkdata[i++] != 0) png_warning(png_ptr, "Invalid sCAL chunk ignored: bad width format"); + else if (!PNG_FP_IS_POSITIVE(state)) + png_warning(png_ptr, "Invalid sCAL chunk ignored: non-positive width"); + else { png_size_t heighti = i; state = 0; - if (png_ptr->chunkdata[i] == 45 /* negative height */ || - !png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) || + if (!png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) || i != slength) png_warning(png_ptr, "Invalid sCAL chunk ignored: bad height format"); + else if (!PNG_FP_IS_POSITIVE(state)) + png_warning(png_ptr, + "Invalid sCAL chunk ignored: non-positive height"); + else /* This is the (only) success case. */ png_set_sCAL_s(png_ptr, info_ptr, png_ptr->chunkdata[0], diff --git a/pngvalid.c b/pngvalid.c index cc675f609..7c9706e43 100644 --- a/pngvalid.c +++ b/pngvalid.c @@ -5281,9 +5281,9 @@ image_transform_png_set_scale_16_add(image_transform *this, IT(scale_16); #undef PT #define PT ITSTRUCT(scale_16) -#endif +#endif /* PNG_READ_SCALE_16_TO_8_SUPPORTED (1.5.4 on) */ -#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED /* the default before 1.5.4 */ +#ifdef PNG_READ_16_TO_8_SUPPORTED /* the default before 1.5.4 */ /* png_set_strip_16 */ static void image_transform_png_set_strip_16_set(PNG_CONST image_transform *this, @@ -5305,18 +5305,28 @@ image_transform_png_set_strip_16_mod(PNG_CONST image_transform *this, if (that->blue_sBIT > 8) that->blue_sBIT = 8; if (that->alpha_sBIT > 8) that->alpha_sBIT = 8; - /* The strip 16 algorithm drops the low 8 bits rather than calculating - * 1/257, so we need to adjust the permitted errors appropriately: - * Notice that this is only relevant prior to the addition of the - * png_set_scale_16 API in 1.5.4 (but 1.5.4+ always defines the above!) + /* Prior to 1.5.4 png_set_strip_16 would use an 'accurate' method if this + * configuration option is set. From 1.5.4 the flag is never set and the + * 'scale' API (above) must be used. */ - { - PNG_CONST double d = (255-128.5)/65535; - that->rede += d; - that->greene += d; - that->bluee += d; - that->alphae += d; - } +# ifdef PNG_READ_ACCURATE_SCALE_SUPPORTED +# if PNG_LIBPNG_VER >= 10504 +# error PNG_READ_ACCURATE_SCALE should not be set +# endif + + /* The strip 16 algorithm drops the low 8 bits rather than calculating + * 1/257, so we need to adjust the permitted errors appropriately: + * Notice that this is only relevant prior to the addition of the + * png_set_scale_16 API in 1.5.4 (but 1.5.4+ always defines the above!) + */ + { + PNG_CONST double d = (255-128.5)/65535; + that->rede += d; + that->greene += d; + that->bluee += d; + that->alphae += d; + } +# endif } this->next->mod(this->next, that, pp, display); @@ -5337,7 +5347,7 @@ image_transform_png_set_strip_16_add(image_transform *this, IT(strip_16); #undef PT #define PT ITSTRUCT(strip_16) -#endif /* PNG_READ_STRIP_16_TO_8_SUPPORTED, from libpng 1.5.4 */ +#endif /* PNG_READ_16_TO_8_SUPPORTED */ #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED /* png_set_strip_alpha */ @@ -6102,7 +6112,12 @@ gamma_info_imp(gamma_display *dp, png_structp pp, png_infop pi) # ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED png_set_scale_16(pp); # else - png_error(pp, "scale16 (16 to 8 bit conversion) not supported"); + /* The following works both in 1.5.4 and earlier versions: */ +# ifdef PNG_READ_16_TO_8_SUPPORTED + png_set_strip_16(pp); +# else + png_error(pp, "scale16 (16 to 8 bit conversion) not supported"); +# endif # endif if (dp->expand16) @@ -6713,8 +6728,12 @@ gamma_component_validate(PNG_CONST char *name, PNG_CONST validate_info *vi, * option has been used and 'inaccurate' scaling is used then the * bit reduction is obtained by simply using the top 8 bits of the * value. + * + * This is only done for older libpng versions when the 'inaccurate' + * (chop) method of scaling was used. */ -# if 0 /*WAS: #ifndef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED */ +# if !PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED && \ + PNG_LIBPNG_VER < 10504 /* This may be required for other components in the future, but * at present the presence of gamma correction effectively * prevents the errors in the component scaling (I don't quite diff --git a/scripts/pnglibconf.dfa b/scripts/pnglibconf.dfa index a718ab943..53a5ef568 100644 --- a/scripts/pnglibconf.dfa +++ b/scripts/pnglibconf.dfa @@ -294,7 +294,9 @@ option READ enables READ_INTERLACING # Disabling READ_16BIT does not disable reading 16-bit PNG files, but it # forces them to be chopped down to 8-bit, and disables any 16-bit # processing after that has happened. You need to be sure to enable -# READ_16_TO_8 when you disable READ_16BIT for this to work properly. +# READ_SCALE_16_TO_8 or READ_STRIP_16_TO_8 when you disable READ_16BIT for +# this to work properly. You should disable the other option if you need to +# ensure a particular convertion (otherwise the app can chose.) option READ_16BIT requires READ enables 16BIT @@ -312,7 +314,8 @@ option READ_SWAP requires READ_TRANSFORMS READ_16BIT option READ_PACKSWAP requires READ_TRANSFORMS option READ_INVERT requires READ_TRANSFORMS option READ_BACKGROUND requires READ_TRANSFORMS enables READ_STRIP_ALPHA -option READ_16_TO_8 requires READ_TRANSFORMS +option READ_STRIP_16_TO_8 requires READ_TRANSFORMS +option READ_SCALE_16_TO_8 requires READ_TRANSFORMS option READ_FILLER requires READ_TRANSFORMS option READ_GAMMA requires READ_TRANSFORMS enables READ_gAMA option READ_GRAY_TO_RGB requires READ_TRANSFORMS @@ -550,14 +553,8 @@ option SAVE_INT_32 requires WRITE # png_save_int_32 is required by the ancillary chunks oFFs and pCAL -# enabled at libpng-1.5.4, was present but disabled by default - -option READ_16_TO_8_ACCURATE_SCALE requires READ_SCALE_16_TO_8 - # added at libpng-1.5.4 -option READ_SCALE_16_TO_8 requires READ_16_TO_8 - option WRITE_OPTIMIZE_CMF requires WRITE option READ_COMPRESSED_TEXT disabled @@ -565,7 +562,6 @@ option READ_iCCP enables READ_COMPRESSED_TEXT option READ_iTXt enables READ_COMPRESSED_TEXT option READ_zTXt enables READ_COMPRESSED_TEXT option READ_COMPRESSED_TEXT enables READ_TEXT -option READ_STRIP_16_TO_8 requires READ_16_TO_8 option WRITE_oFFs enables SAVE_INT_32 option WRITE_pCAL enables SAVE_INT_32