diff --git a/src/libpng/png.c b/src/libpng/png.c index 7d09b0dbd..eed313619 100644 --- a/src/libpng/png.c +++ b/src/libpng/png.c @@ -1,7 +1,7 @@ /* png.c - location for general purpose libpng functions * - * Last changed in libpng 1.5.1 [February 3, 2011] + * Last changed in libpng 1.5.4 [July 7, 2011] * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -14,7 +14,7 @@ #include "pngpriv.h" /* Generate a compiler error if there is an old png.h in the search path. */ -typedef png_libpng_version_1_5_2 Your_png_h_is_not_version_1_5_2; +typedef png_libpng_version_1_5_4 Your_png_h_is_not_version_1_5_4; /* Tells libpng that we have already handled the first "num_bytes" bytes * of the PNG file signature. If the PNG data is embedded into another @@ -137,6 +137,61 @@ png_calculate_crc(png_structp png_ptr, png_const_bytep ptr, png_size_t length) png_ptr->crc = crc32(png_ptr->crc, ptr, (uInt)length); } +/* Check a user supplied version number, called from both read and write + * functions that create a png_struct + */ +int +png_user_version_check(png_structp png_ptr, png_const_charp user_png_ver) +{ + if (user_png_ver) + { + int i = 0; + + do + { + if (user_png_ver[i] != png_libpng_ver[i]) + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + } while (png_libpng_ver[i++]); + } + + else + png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; + + if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) + { + /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so + * we must recompile any applications that use any older library version. + * For versions after libpng 1.0, we will be compatible, so we need + * only check the first digit. + */ + if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || + (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || + (user_png_ver[0] == '0' && user_png_ver[2] < '9')) + { +#ifdef PNG_WARNINGS_SUPPORTED + size_t pos = 0; + char m[128]; + + pos = png_safecat(m, sizeof m, pos, "Application built with libpng-"); + pos = png_safecat(m, sizeof m, pos, user_png_ver); + pos = png_safecat(m, sizeof m, pos, " but running with "); + pos = png_safecat(m, sizeof m, pos, png_libpng_ver); + + png_warning(png_ptr, m); +#endif + +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags = 0; +#endif + + return 0; + } + } + + /* Success return. */ + return 1; +} + /* Allocate the memory for an info_struct for the application. We don't * really need the png_ptr, but it could potentially be useful in the * future. This should be used in favour of malloc(png_sizeof(png_info)) @@ -291,12 +346,10 @@ png_free_data(png_structp png_ptr, png_infop info_ptr, png_uint_32 mask, /* Free any sCAL entry */ if ((mask & PNG_FREE_SCAL) & info_ptr->free_me) { -#if defined(PNG_FIXED_POINT_SUPPORTED) && !defined(PNG_FLOATING_POINT_SUPPORTED) png_free(png_ptr, info_ptr->scal_s_width); png_free(png_ptr, info_ptr->scal_s_height); info_ptr->scal_s_width = NULL; info_ptr->scal_s_height = NULL; -#endif info_ptr->valid &= ~PNG_INFO_sCAL; } #endif @@ -518,28 +571,37 @@ png_convert_to_rfc1123(png_structp png_ptr, png_const_timep ptime) if (png_ptr == NULL) return (NULL); - if (png_ptr->time_buffer == NULL) { - png_ptr->time_buffer = (png_charp)png_malloc(png_ptr, (png_uint_32)(29* - png_sizeof(char))); + size_t pos = 0; + char number_buf[5]; /* enough for a four digit year */ + +# define APPEND_STRING(string)\ + pos = png_safecat(png_ptr->time_buffer, sizeof png_ptr->time_buffer,\ + pos, (string)) +# define APPEND_NUMBER(format, value)\ + APPEND_STRING(PNG_FORMAT_NUMBER(number_buf, format, (value))) +# define APPEND(ch)\ + if (pos < (sizeof png_ptr->time_buffer)-1)\ + png_ptr->time_buffer[pos++] = (ch) + + APPEND_NUMBER(PNG_NUMBER_FORMAT_u, (unsigned)ptime->day % 32); + APPEND(' '); + APPEND_STRING(short_months[(ptime->month - 1) % 12]); + APPEND(' '); + APPEND_NUMBER(PNG_NUMBER_FORMAT_u, ptime->year); + APPEND(' '); + APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->hour % 24); + APPEND(':'); + APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->minute % 60); + APPEND(':'); + APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->second % 61); + APPEND_STRING(" +0000"); /* This reliably terminates the buffer */ + +# undef APPEND +# undef APPEND_NUMBER +# undef APPEND_STRING } -# ifdef USE_FAR_KEYWORD - { - char near_time_buf[29]; - png_snprintf6(near_time_buf, 29, "%d %s %d %02d:%02d:%02d +0000", - ptime->day % 32, short_months[(ptime->month - 1) % 12], - ptime->year, ptime->hour % 24, ptime->minute % 60, - ptime->second % 61); - png_memcpy(png_ptr->time_buffer, near_time_buf, - 29*png_sizeof(char)); - } -# else - png_snprintf6(png_ptr->time_buffer, 29, "%d %s %d %02d:%02d:%02d +0000", - ptime->day % 32, short_months[(ptime->month - 1) % 12], - ptime->year, ptime->hour % 24, ptime->minute % 60, - ptime->second % 61); -# endif return png_ptr->time_buffer; } # endif /* PNG_TIME_RFC1123_SUPPORTED */ @@ -555,13 +617,13 @@ png_get_copyright(png_const_structp png_ptr) #else # ifdef __STDC__ return PNG_STRING_NEWLINE \ - "libpng version 1.5.2 - March 31, 2011" PNG_STRING_NEWLINE \ + "libpng version 1.5.4 - July 7, 2011" PNG_STRING_NEWLINE \ "Copyright (c) 1998-2011 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \ "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \ PNG_STRING_NEWLINE; # else - return "libpng version 1.5.2 - March 31, 2011\ + return "libpng version 1.5.4 - July 7, 2011\ Copyright (c) 1998-2011 Glenn Randers-Pehrson\ Copyright (c) 1996-1997 Andreas Dilger\ Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc."; @@ -681,6 +743,13 @@ png_check_cHRM_fixed(png_structp png_ptr, if (png_ptr == NULL) return 0; + /* (x,y,z) values are first limited to 0..100000 (PNG_FP_1), the white + * y must also be greater than 0. To test for the upper limit calculate + * (PNG_FP_1-y) - x must be <= to this for z to be >= 0 (and the expression + * cannot overflow.) At this point we know x and y are >= 0 and (x+y) is + * <= PNG_FP_1. The previous test on PNG_MAX_UINT_31 is removed because it + * pointless (and it produces compiler warnings!) + */ if (white_x < 0 || white_y <= 0 || red_x < 0 || red_y < 0 || green_x < 0 || green_y < 0 || @@ -690,38 +759,26 @@ png_check_cHRM_fixed(png_structp png_ptr, "Ignoring attempt to set negative chromaticity value"); ret = 0; } - if (white_x > (png_fixed_point)PNG_UINT_31_MAX || - white_y > (png_fixed_point)PNG_UINT_31_MAX || - red_x > (png_fixed_point)PNG_UINT_31_MAX || - red_y > (png_fixed_point)PNG_UINT_31_MAX || - green_x > (png_fixed_point)PNG_UINT_31_MAX || - green_y > (png_fixed_point)PNG_UINT_31_MAX || - blue_x > (png_fixed_point)PNG_UINT_31_MAX || - blue_y > (png_fixed_point)PNG_UINT_31_MAX ) - { - png_warning(png_ptr, - "Ignoring attempt to set chromaticity value exceeding 21474.83"); - ret = 0; - } - if (white_x > 100000L - white_y) + /* And (x+y) must be <= PNG_FP_1 (so z is >= 0) */ + if (white_x > PNG_FP_1 - white_y) { png_warning(png_ptr, "Invalid cHRM white point"); ret = 0; } - if (red_x > 100000L - red_y) + if (red_x > PNG_FP_1 - red_y) { png_warning(png_ptr, "Invalid cHRM red point"); ret = 0; } - if (green_x > 100000L - green_y) + if (green_x > PNG_FP_1 - green_y) { png_warning(png_ptr, "Invalid cHRM green point"); ret = 0; } - if (blue_x > 100000L - blue_y) + if (blue_x > PNG_FP_1 - blue_y) { png_warning(png_ptr, "Invalid cHRM blue point"); ret = 0; @@ -763,7 +820,7 @@ png_check_IHDR(png_structp png_ptr, } # ifdef PNG_SET_USER_LIMITS_SUPPORTED - if (width > png_ptr->user_width_max || width > PNG_USER_WIDTH_MAX) + if (width > png_ptr->user_width_max) # else if (width > PNG_USER_WIDTH_MAX) @@ -774,7 +831,7 @@ png_check_IHDR(png_structp png_ptr, } # ifdef PNG_SET_USER_LIMITS_SUPPORTED - if (height > png_ptr->user_height_max || height > PNG_USER_HEIGHT_MAX) + if (height > png_ptr->user_height_max) # else if (height > PNG_USER_HEIGHT_MAX) # endif @@ -889,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, @@ -911,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; @@ -967,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). @@ -989,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 */ @@ -997,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 */ @@ -1033,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 */ @@ -1102,7 +1155,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size, if (fp < 0) { fp = -fp; - *ascii++ = 45; /* '-' PLUS 1 TOTAL 1*/ + *ascii++ = 45; /* '-' PLUS 1 TOTAL 1 */ --size; } @@ -1329,7 +1382,7 @@ png_ascii_from_fp(png_structp png_ptr, png_charp ascii, png_size_t size, */ size -= cdigits; - *ascii++ = 69, --size; /* 'E': PLUS 1 TOTAL 2+precision*/ + *ascii++ = 69, --size; /* 'E': PLUS 1 TOTAL 2+precision */ if (exp_b10 < 0) { *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */ @@ -1401,7 +1454,7 @@ png_ascii_from_fixed(png_structp png_ptr, png_charp ascii, png_size_t size, if (num <= 0x80000000U) /* else overflowed */ { - unsigned int ndigits = 0, first = 16/*flag value*/; + unsigned int ndigits = 0, first = 16 /* flag value */; char digits[10]; while (num) @@ -1495,7 +1548,7 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times, r /= divisor; r = floor(r+.5); - /* A png_fixed_point is a 32 bit integer. */ + /* A png_fixed_point is a 32-bit integer. */ if (r <= 2147483647. && r >= -2147483648.) { *res = (png_fixed_point)r; @@ -1540,7 +1593,7 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times, if (s32 < D) /* else overflow */ { - /* s32.s00 is now the 64 bit product, do a standard + /* s32.s00 is now the 64-bit product, do a standard * division, we know that s32 < D, so the maximum * required shift is 31. */ @@ -1683,7 +1736,7 @@ png_reciprocal2(png_fixed_point a, png_fixed_point b) * 2010: moved from pngset.c) */ /* * Multiply two 32-bit numbers, V1 and V2, using 32-bit - * arithmetic, to produce a 64 bit result in the HI/LO words. + * arithmetic, to produce a 64-bit result in the HI/LO words. * * A B * x C D @@ -1727,17 +1780,17 @@ png_64bit_product (long v1, long v2, unsigned long *hi_product, /* Fixed point gamma. * * To calculate gamma this code implements fast log() and exp() calls using only - * fixed point arithmetic. This code has sufficient precision for either 8 or - * 16 bit sample values. + * fixed point arithmetic. This code has sufficient precision for either 8-bit + * or 16-bit sample values. * * The tables used here were calculated using simple 'bc' programs, but C double * precision floating point arithmetic would work fine. The programs are given * at the head of each table. * - * 8 bit log table + * 8-bit log table * This is a table of -log(value/255)/log(2) for 'value' in the range 128 to - * 255, so it's the base 2 logarithm of a normalized 8 bit floating point - * mantissa. The numbers are 32 bit fractions. + * 255, so it's the base 2 logarithm of a normalized 8-bit floating point + * mantissa. The numbers are 32-bit fractions. */ static png_uint_32 png_8bit_l2[128] = @@ -1768,10 +1821,10 @@ png_8bit_l2[128] = 172473545U, 147538590U, 122703574U, 97967701U, 73330182U, 48790236U, 24347096U, 0U #if 0 - /* The following are the values for 16 bit tables - these work fine for the 8 - * bit conversions but produce very slightly larger errors in the 16 bit log - * (about 1.2 as opposed to 0.7 absolute error in the final value). To use - * these all the shifts below must be adjusted appropriately. + /* The following are the values for 16-bit tables - these work fine for the + * 8-bit conversions but produce very slightly larger errors in the 16-bit + * log (about 1.2 as opposed to 0.7 absolute error in the final value). To + * use these all the shifts below must be adjusted appropriately. */ 65166, 64430, 63700, 62976, 62257, 61543, 60835, 60132, 59434, 58741, 58054, 57371, 56693, 56020, 55352, 54689, 54030, 53375, 52726, 52080, 51439, 50803, @@ -1788,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; @@ -1814,11 +1867,11 @@ png_log8bit(unsigned int x) return (png_int_32)((lg2 << 16) + ((png_8bit_l2[x-128]+32768)>>16)); } -/* The above gives exact (to 16 binary places) log2 values for 8 bit images, - * for 16 bit images we use the most significant 8 bits of the 16 bit value to +/* The above gives exact (to 16 binary places) log2 values for 8-bit images, + * for 16-bit images we use the most significant 8 bits of the 16-bit value to * get an approximation then multiply the approximation by a correction factor * determined by the remaining up to 8 bits. This requires an additional step - * in the 16 bit case. + * in the 16-bit case. * * We want log2(value/65535), we have log2(v'/255), where: * @@ -1827,8 +1880,8 @@ png_log8bit(unsigned int x) * * So f is value/v', which is equal to (256+v''/v') since v' is in the range 128 * to 255 and v'' is in the range 0 to 255 f will be in the range 256 to less - * than 258. The final factor also needs to correct for the fact that our 8 bit - * value is scaled by 255, whereas the 16 bit values must be scaled by 65535. + * than 258. The final factor also needs to correct for the fact that our 8-bit + * value is scaled by 255, whereas the 16-bit values must be scaled by 65535. * * This gives a final formula using a calculated value 'x' which is value/v' and * scaling by 65536 to match the above table: @@ -1838,13 +1891,13 @@ png_log8bit(unsigned int x) * Since these numbers are so close to '1' we can use simple linear * interpolation between the two end values 256/257 (result -368.61) and 258/257 * (result 367.179). The values used below are scaled by a further 64 to give - * 16 bit precision in the interpolation: + * 16-bit precision in the interpolation: * * Start (256): -23591 * 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; @@ -1865,7 +1918,7 @@ png_log16bit(png_uint_32 x) if ((x & 0x8000) == 0) lg2 += 1, x <<= 1; - /* Calculate the base logarithm from the top 8 bits as a 28 bit fractional + /* Calculate the base logarithm from the top 8 bits as a 28-bit fractional * value. */ lg2 <<= 28; @@ -1895,18 +1948,18 @@ png_log16bit(png_uint_32 x) return (png_int_32)((lg2 + 2048) >> 12); } -/* The 'exp()' case must invert the above, taking a 20 bit fixed point - * logarithmic value and returning a 16 or 8 bit number as appropriate. In +/* The 'exp()' case must invert the above, taking a 20-bit fixed point + * logarithmic value and returning a 16 or 8-bit number as appropriate. In * each case only the low 16 bits are relevant - the fraction - since the * integer bits (the top 4) simply determine a shift. * - * The worst case is the 16 bit distinction between 65535 and 65534, this + * The worst case is the 16-bit distinction between 65535 and 65534, this * requires perhaps spurious accuracty in the decoding of the logarithm to * distinguish log2(65535/65534.5) - 10^-5 or 17 bits. There is little chance * of getting this accuracy in practice. * * To deal with this the following exp() function works out the exponent of the - * frational part of the logarithm by using an accurate 32 bit value from the + * frational part of the logarithm by using an accurate 32-bit value from the * top four fractional bits then multiplying in the remaining bits. */ static png_uint_32 @@ -1915,7 +1968,7 @@ png_32bit_exp[16] = # if PNG_DO_BC for (i=0;i<16;++i) { .5 + e(-i/16*l(2))*2^32; } # endif - /* NOTE: the first entry is deliberately set to the maximum 32 bit value. */ + /* NOTE: the first entry is deliberately set to the maximum 32-bit value. */ 4294967295U, 4112874773U, 3938502376U, 3771522796U, 3611622603U, 3458501653U, 3311872529U, 3171459999U, 3037000500U, 2908241642U, 2784941738U, 2666869345U, 2553802834U, 2445529972U, 2341847524U, 2242560872U @@ -1938,12 +1991,12 @@ 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) */ { - /* Obtain a 4 bit approximation */ + /* Obtain a 4-bit approximation */ png_uint_32 e = png_32bit_exp[(x >> 12) & 0xf]; /* Incorporate the low 12 bits - these decrease the returned value by @@ -1986,13 +2039,13 @@ 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: */ + /* Get a 32-bit value: */ png_uint_32 x = png_exp(lg2); - /* Convert the 32 bit value to 0..255 by multiplying by 256-1, note that the + /* Convert the 32-bit value to 0..255 by multiplying by 256-1, note that the * second, rounding, step can't overflow because of the first, subtraction, * step. */ @@ -2000,13 +2053,13 @@ 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: */ + /* Get a 32-bit value: */ png_uint_32 x = png_exp(lg2); - /* Convert the 32 bit value to 0..65535 by multiplying by 65536-1: */ + /* Convert the 32-bit value to 0..65535 by multiplying by 65536-1: */ x -= x >> 16; return (png_uint_16)((x + 32767U) >> 16); } @@ -2059,9 +2112,9 @@ png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val) } /* This does the right thing based on the bit_depth field of the - * png_struct, interpreting values as 8 or 16 bit. While the result - * is nominally a 16 bit value if bit depth is 8 then the result is - * 8 bit (as are the arguments.) + * png_struct, interpreting values as 8-bit or 16-bit. While the result + * is nominally a 16-bit value if bit depth is 8 then the result is + * 8-bit (as are the arguments.) */ png_uint_16 /* PRIVATE */ png_gamma_correct(png_structp png_ptr, unsigned int value, @@ -2084,7 +2137,7 @@ png_gamma_significant(png_fixed_point gamma_val) gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED; } -/* Internal function to build a single 16 bit table - the table consists of +/* Internal function to build a single 16-bit table - the table consists of * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount * to shift the input values right (or 16-number_of_signifiant_bits). * @@ -2111,7 +2164,7 @@ png_build_16bit_table(png_structp png_ptr, png_uint_16pp *ptable, (png_uint_16p)png_malloc(png_ptr, 256 * png_sizeof(png_uint_16)); /* The 'threshold' test is repeated here because it can arise for one of - * the 16 bit tables even if the others don't hit it. + * the 16-bit tables even if the others don't hit it. */ if (png_gamma_significant(gamma_val)) { @@ -2173,7 +2226,7 @@ png_build_16to8_table(png_structp png_ptr, png_uint_16pp *ptable, (png_uint_16pp)png_calloc(png_ptr, num * png_sizeof(png_uint_16p)); /* 'num' is the number of tables and also the number of low bits of low - * bits of the input 16 bit value used to select a table. Each table is + * bits of the input 16-bit value used to select a table. Each table is * itself index by the high 8 bits of the value. */ for (i = 0; i < num; i++) @@ -2183,24 +2236,24 @@ png_build_16to8_table(png_structp png_ptr, png_uint_16pp *ptable, /* 'gamma_val' is set to the reciprocal of the value calculated above, so * pow(out,g) is an *input* value. 'last' is the last input value set. * - * In the loop 'i' is used to find output values. Since the output is 8 - * bit there are only 256 possible values. The tables are set up to + * In the loop 'i' is used to find output values. Since the output is + * 8-bit there are only 256 possible values. The tables are set up to * select the closest possible output value for each input by finding * the input value at the boundary between each pair of output values * and filling the table up to that boundary with the lower output * value. * - * The boundary values are 0.5,1.5..253.5,254.5. Since these are 9 bit - * values the code below uses a 16 bit value in i; the values start at + * The boundary values are 0.5,1.5..253.5,254.5. Since these are 9-bit + * values the code below uses a 16-bit value in i; the values start at * 128.5 (for 0.5) and step by 257, for a total of 254 values (the last * entries are filled with 255). Start i at 128 and fill all 'last' * table entries <= 'max' */ last = 0; - for (i = 0; i < 255; ++i) /* 8 bit output value */ + for (i = 0; i < 255; ++i) /* 8-bit output value */ { /* Find the corresponding maximum input value */ - png_uint_16 out = (png_uint_16)(i * 257U); /* 16 bit output value */ + png_uint_16 out = (png_uint_16)(i * 257U); /* 16-bit output value */ /* Find the boundary value in 16 bits: */ png_uint_32 bound = png_gamma_16bit_correct(out+128U, gamma_val); @@ -2223,7 +2276,7 @@ png_build_16to8_table(png_structp png_ptr, png_uint_16pp *ptable, } } -/* Build a single 8 bit table: same as the 16 bit case but much simpler (and +/* Build a single 8-bit table: same as the 16-bit case but much simpler (and * typically much faster). Note that libpng currently does no sBIT processing * (apparently contrary to the spec) so a 256 entry table is always generated. */ @@ -2258,8 +2311,9 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth) png_ptr->screen_gamma) : PNG_FP_1); #if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - if (png_ptr->transformations & ((PNG_BACKGROUND) | PNG_RGB_TO_GRAY)) + if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) { png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1, png_reciprocal(png_ptr->gamma)); @@ -2268,7 +2322,7 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth) png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) : png_ptr->gamma/* Probably doing rgb_to_gray */); } -#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */ +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ } else { @@ -2287,7 +2341,7 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth) else sig_bit = png_ptr->sig_bit.gray; - /* 16 bit gamma code uses this equation: + /* 16-bit gamma code uses this equation: * * ov = table[(iv & 0xff) >> gamma_shift][iv >> 8] * @@ -2302,7 +2356,7 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth) * * So the table 'n' corresponds to all those 'iv' of: * - * ..<(n+1 << gamma_shift)-1> + * ..<(n+1 << gamma_shift)-1> * */ if (sig_bit > 0 && sig_bit < 16U) @@ -2311,7 +2365,7 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth) else shift = 0; /* keep all 16 bits */ - if (png_ptr->transformations & PNG_16_TO_8) + if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) { /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively * the significant bits in the *input* when the output will @@ -2327,7 +2381,12 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth) png_ptr->gamma_shift = shift; #ifdef PNG_16BIT_SUPPORTED - if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND)) + /* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now + * PNG_COMPOSE). This effectively smashed the background calculation for + * 16-bit output because the 8-bit table assumes the result will be reduced + * to 8 bits. + */ + if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) #endif png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift, png_ptr->screen_gamma > 0 ? png_product2(png_ptr->gamma, @@ -2341,8 +2400,9 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth) #endif #if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) - if (png_ptr->transformations & (PNG_BACKGROUND | PNG_RGB_TO_GRAY)) + if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) { png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift, png_reciprocal(png_ptr->gamma)); @@ -2355,7 +2415,7 @@ png_build_gamma_table(png_structp png_ptr, int bit_depth) png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) : png_ptr->gamma/* Probably doing rgb_to_gray */); } -#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_RGB_TO_GRAY_SUPPORTED */ +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ } } #endif /* READ_GAMMA */ diff --git a/src/libpng/png.h b/src/libpng/png.h index 0af42b170..c655a51af 100644 --- a/src/libpng/png.h +++ b/src/libpng/png.h @@ -1,7 +1,7 @@ /* png.h - header file for PNG reference library * - * libpng version 1.5.2 - March 31, 2011 + * libpng version 1.5.4 - July 7, 2011 * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -11,7 +11,7 @@ * Authors and maintainers: * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger - * libpng versions 0.97, January 1998, through 1.5.2 - March 31, 2011: Glenn + * libpng versions 0.97, January 1998, through 1.5.4 - July 7, 2011: Glenn * See also "Contributing Authors", below. * * Note about libpng version numbers: @@ -150,6 +150,13 @@ * 1.5.2beta01-03 15 10502 15.so.15.2[.0] * 1.5.2rc01-03 15 10502 15.so.15.2[.0] * 1.5.2 15 10502 15.so.15.2[.0] + * 1.5.3beta01-10 15 10503 15.so.15.3[.0] + * 1.5.3rc01-02 15 10503 15.so.15.3[.0] + * 1.5.3beta11 15 10503 15.so.15.3[.0] + * 1.5.3 [omitted] + * 1.5.4beta01-08 15 10504 15.so.15.4[.0] + * 1.5.4rc01 15 10504 15.so.15.4[.0] + * 1.5.4 15 10504 15.so.15.4[.0] * * Henceforth the source version will match the shared-library major * and minor numbers; the shared-library major version number will be @@ -181,7 +188,7 @@ * * This code is released under the libpng license. * - * libpng versions 1.2.6, August 15, 2004, through 1.5.2, March 31, 2011, are + * libpng versions 1.2.6, August 15, 2004, through 1.5.4, July 7, 2011, are * Copyright (c) 2004, 2006-2011 Glenn Randers-Pehrson, and are * distributed according to the same disclaimer and license as libpng-1.2.5 * with the following individual added to the list of Contributing Authors: @@ -293,25 +300,24 @@ * Y2K compliance in libpng: * ========================= * - * March 31, 2011 + * July 7, 2011 * * Since the PNG Development group is an ad-hoc body, we can't make * an official declaration. * * This is your unofficial assurance that libpng from version 0.71 and - * upward through 1.5.2 are Y2K compliant. It is my belief that + * upward through 1.5.4 are Y2K compliant. It is my belief that * earlier versions were also Y2K compliant. * - * Libpng only has three year fields. One is a 2-byte unsigned integer - * that will hold years up to 65535. The other two hold the date in text + * Libpng only has two year fields. One is a 2-byte unsigned integer + * that will hold years up to 65535. The other holds the date in text * format, and will hold years up to 9999. * * The integer is * "png_uint_16 year" in png_time_struct. * - * The strings are - * "png_charp time_buffer" in png_struct and - * "near_time_buffer", which is a local character string in png.c. + * The string is + * "png_char time_buffer" in png_struct * * There are seven time-related functions: * png.c: png_convert_to_rfc_1123() in png.c @@ -355,9 +361,9 @@ */ /* Version information for png.h - this should match the version in png.c */ -#define PNG_LIBPNG_VER_STRING "1.5.2" +#define PNG_LIBPNG_VER_STRING "1.5.4" #define PNG_HEADER_VERSION_STRING \ - " libpng version 1.5.2 - March 31, 2011\n" + " libpng version 1.5.4 - July 7, 2011\n" #define PNG_LIBPNG_VER_SONUM 15 #define PNG_LIBPNG_VER_DLLNUM 15 @@ -365,7 +371,7 @@ /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ #define PNG_LIBPNG_VER_MAJOR 1 #define PNG_LIBPNG_VER_MINOR 5 -#define PNG_LIBPNG_VER_RELEASE 2 +#define PNG_LIBPNG_VER_RELEASE 4 /* This should match the numeric part of the final component of * PNG_LIBPNG_VER_STRING, omitting any leading zero: */ @@ -395,7 +401,7 @@ * version 1.0.0 was mis-numbered 100 instead of 10000). From * version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release */ -#define PNG_LIBPNG_VER 10502 /* 1.5.2 */ +#define PNG_LIBPNG_VER 10504 /* 1.5.4 */ /* Library configuration: these options cannot be changed after * the library has been built. @@ -517,7 +523,7 @@ extern "C" { /* This triggers a compiler error in png.c, if png.c and png.h * do not agree upon the version number. */ -typedef char* png_libpng_version_1_5_2; +typedef char* png_libpng_version_1_5_4; /* Three color definitions. The order of the red, green, and blue, (and the * exact size) is not important, although the size of the fields need to @@ -594,7 +600,7 @@ typedef png_sPLT_t FAR * FAR * png_sPLT_tpp; * and whether that contents is compressed or not. The "key" field * points to a regular zero-terminated C string. The "text", "lang", and * "lang_key" fields can be regular C strings, empty strings, or NULL pointers. - * However, the * structure returned by png_get_text() will always contain + * However, the structure returned by png_get_text() will always contain * regular zero-terminated C strings (possibly empty), never NULL pointers, * so they can be safely used in printf() and other string-handling functions. */ @@ -665,12 +671,24 @@ typedef struct png_unknown_chunk_t /* libpng-using applications should NOT directly modify this byte. */ png_byte location; /* mode of operation at read time */ } + + png_unknown_chunk; typedef png_unknown_chunk FAR * png_unknown_chunkp; typedef PNG_CONST png_unknown_chunk FAR * png_const_unknown_chunkp; typedef png_unknown_chunk FAR * FAR * png_unknown_chunkpp; #endif +/* Values for the unknown chunk location byte */ + +#define PNG_HAVE_IHDR 0x01 +#define PNG_HAVE_PLTE 0x02 +#define PNG_AFTER_IDAT 0x08 + +/* The complete definition of png_info has, as of libpng-1.5.0, + * been moved into a separate header file that is not accessible to + * applications. Read libpng-manual.txt or libpng.3 for more info. + */ typedef struct png_info_def png_info; typedef png_info FAR * png_infop; typedef PNG_CONST png_info FAR * png_const_infop; @@ -686,6 +704,8 @@ typedef png_info FAR * FAR * png_infopp; */ #define PNG_FP_1 100000 #define PNG_FP_HALF 50000 +#define PNG_FP_MAX ((png_fixed_point)0x7fffffffL) +#define PNG_FP_MIN (-PNG_FP_MAX) /* These describe the color_type field in png_info. */ /* color type masks */ @@ -792,6 +812,14 @@ typedef struct png_row_info_struct typedef png_row_info FAR * png_row_infop; typedef png_row_info FAR * FAR * png_row_infopp; +/* The complete definition of png_struct has, as of libpng-1.5.0, + * been moved into a separate header file that is not accessible to + * applications. Read libpng-manual.txt or libpng.3 for more info. + */ +typedef struct png_struct_def png_struct; +typedef PNG_CONST png_struct FAR * png_const_structp; +typedef png_struct FAR * png_structp; + /* These are the function types for the I/O functions and for the functions * that allow the user to override the default I/O functions with his or her * own. The png_error_ptr type should match that of user-supplied warning @@ -800,10 +828,6 @@ typedef png_row_info FAR * FAR * png_row_infopp; * modify the buffer it is passed. The 'read' function, on the other hand, is * expected to return the read data in the buffer. */ -typedef struct png_struct_def png_struct; -typedef PNG_CONST png_struct FAR * png_const_structp; -typedef png_struct FAR * png_structp; - typedef PNG_CALLBACK(void, *png_error_ptr, (png_structp, png_const_charp)); typedef PNG_CALLBACK(void, *png_rw_ptr, (png_structp, png_bytep, png_size_t)); typedef PNG_CALLBACK(void, *png_flush_ptr, (png_structp)); @@ -845,25 +869,18 @@ typedef PNG_CALLBACK(void, *png_unknown_chunk_ptr, (png_structp)); #endif #ifdef PNG_SETJMP_SUPPORTED -/* This must match the function definition in , and the - * application must include this before png.h to obtain the definition - * of jmp_buf. The function is required to be PNG_NORETURN. (Note that - * PNG_PTR_NORETURN is used here because current versions of the Microsoft - * C compiler do not support the PNG_NORETURN attribute on a pointer.) +/* This must match the function definition in , and the application + * must include this before png.h to obtain the definition of jmp_buf. The + * function is required to be PNG_NORETURN, but this is not checked. If the + * function does return the application will crash via an abort() or similar + * system level call. * - * If you get a type warning from the compiler when linking against this line - * then your compiler has 'longjmp' that does not match the requirements of the - * compiler that built libpng. You will have to write a wrapper function for - * your compiler's longjmp and call png_set_longjmp_fn directly (not via the - * png_jmpbuf macro.) - * - * If you get a warning here while building the library you will need to make + * If you get a warning here while building the library you may need to make * changes to ensure that pnglibconf.h records the calling convention used by * your compiler. This may be very difficult - try using a different compiler * to build the library! */ -typedef PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), - PNG_PTR_NORETURN); +PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef); #endif /* Transform masks for the high-level interface */ @@ -885,6 +902,9 @@ typedef PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), #define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */ /* Added to libpng-1.4.0 */ #define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */ +/* Added to libpng-1.5.4 */ +#define PNG_TRANSFORM_EXPAND_16 0x4000 /* read only */ +#define PNG_TRANSFORM_SCALE_16 0x8000 /* read only */ /* Flags for MNG supported features */ #define PNG_FLAG_MNG_EMPTY_PLTE 0x01 @@ -1079,7 +1099,7 @@ PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structp png_ptr)); #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED -/* Expand to 16 bit channels, forces conversion of palette to RGB and expansion +/* Expand to 16-bit channels, forces conversion of palette to RGB and expansion * of a tRNS chunk if present. */ PNG_EXPORT(221, void, png_set_expand_16, (png_structp png_ptr)); @@ -1106,8 +1126,219 @@ PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structp png_ptr)); #endif +#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth, png_colorp palette)); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +/* How the alpha channel is interpreted - this affects how the color channels of + * a PNG file are returned when an alpha channel, or tRNS chunk in a palette + * file, is present. + * + * This has no effect on the way pixels are written into a PNG output + * datastream. The color samples in a PNG datastream are never premultiplied + * with the alpha samples. + * + * The default is to return data according to the PNG specification: the alpha + * channel is a linear measure of the contribution of the pixel to the + * corresponding composited pixel. The gamma encoded color channels must be + * scaled according to the contribution and to do this it is necessary to undo + * the encoding, scale the color values, perform the composition and reencode + * the values. This is the 'PNG' mode. + * + * The alternative is to 'associate' the alpha with the color information by + * storing color channel values that have been scaled by the alpha. The + * advantage is that the color channels can be resampled (the image can be + * scaled) in this form. The disadvantage is that normal practice is to store + * linear, not (gamma) encoded, values and this requires 16-bit channels for + * still images rather than the 8-bit channels that are just about sufficient if + * gamma encoding is used. In addition all non-transparent pixel values, + * including completely opaque ones, must be gamma encoded to produce the final + * image. This is the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' mode (the + * latter being the two common names for associated alpha color channels.) + * + * Since it is not necessary to perform arithmetic on opaque color values so + * long as they are not to be resampled and are in the final color space it is + * possible to optimize the handling of alpha by storing the opaque pixels in + * the PNG format (adjusted for the output color space) while storing partially + * opaque pixels in the standard, linear, format. The accuracy required for + * standard alpha composition is relatively low, because the pixels are + * isolated, therefore typically the accuracy loss in storing 8-bit linear + * values is acceptable. (This is not true if the alpha channel is used to + * simulate transparency over large areas - use 16 bits or the PNG mode in + * this case!) This is the 'OPTIMIZED' mode. For this mode a pixel is + * treated as opaque only if the alpha value is equal to the maximum value. + * + * The final choice is to gamma encode the alpha channel as well. This is + * broken because, in practice, no implementation that uses this choice + * correctly undoes the encoding before handling alpha composition. Use this + * choice only if other serious errors in the software or hardware you use + * mandate it; the typical serious error is for dark halos to appear around + * opaque areas of the composited PNG image because of arithmetic overflow. + * + * The API function png_set_alpha_mode specifies which of these choices to use + * with an enumerated 'mode' value and the gamma of the required output: + */ +#define PNG_ALPHA_PNG 0 /* according to the PNG standard */ +#define PNG_ALPHA_STANDARD 1 /* according to Porter/Duff */ +#define PNG_ALPHA_ASSOCIATED 1 /* as above; this is the normal practice */ +#define PNG_ALPHA_PREMULTIPLIED 1 /* as above */ +#define PNG_ALPHA_OPTIMIZED 2 /* 'PNG' for opaque pixels, else 'STANDARD' */ +#define PNG_ALPHA_BROKEN 3 /* the alpha channel is gamma encoded */ + +PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structp png_ptr, int mode, + double output_gamma)); +PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structp png_ptr, + int mode, png_fixed_point output_gamma)); +#endif + +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED) +/* The output_gamma value is a screen gamma in libpng terminology: it expresses + * how to decode the output values, not how they are encoded. The values used + * correspond to the normal numbers used to describe the overall gamma of a + * computer display system; for example 2.2 for an sRGB conformant system. The + * values are scaled by 100000 in the _fixed version of the API (so 220000 for + * sRGB.) + * + * The inverse of the value is always used to provide a default for the PNG file + * encoding if it has no gAMA chunk and if png_set_gamma() has not been called + * to override the PNG gamma information. + * + * When the ALPHA_OPTIMIZED mode is selected the output gamma is used to encode + * opaque pixels however pixels with lower alpha values are not encoded, + * regardless of the output gamma setting. + * + * When the standard Porter Duff handling is requested with mode 1 the output + * encoding is set to be linear and the output_gamma value is only relevant + * as a default for input data that has no gamma information. The linear output + * encoding will be overridden if png_set_gamma() is called - the results may be + * highly unexpected! + * + * The following numbers are derived from the sRGB standard and the research + * behind it. sRGB is defined to be approximated by a PNG gAMA chunk value of + * 0.45455 (1/2.2) for PNG. The value implicitly includes any viewing + * correction required to take account of any differences in the color + * environment of the original scene and the intended display environment; the + * value expresses how to *decode* the image for display, not how the original + * data was *encoded*. + * + * sRGB provides a peg for the PNG standard by defining a viewing environment. + * sRGB itself, and earlier TV standards, actually use a more complex transform + * (a linear portion then a gamma 2.4 power law) than PNG can express. (PNG is + * limited to simple power laws.) By saying that an image for direct display on + * an sRGB conformant system should be stored with a gAMA chunk value of 45455 + * (11.3.3.2 and 11.3.3.5 of the ISO PNG specification) the PNG specification + * makes it possible to derive values for other display systems and + * environments. + * + * The Mac value is deduced from the sRGB based on an assumption that the actual + * extra viewing correction used in early Mac display systems was implemented as + * a power 1.45 lookup table. + * + * Any system where a programmable lookup table is used or where the behavior of + * the final display device characteristics can be changed requires system + * specific code to obtain the current characteristic. However this can be + * difficult and most PNG gamma correction only requires an approximate value. + * + * By default, if png_set_alpha_mode() is not called, libpng assumes that all + * values are unencoded, linear, values and that the output device also has a + * linear characteristic. This is only very rarely correct - it is invariably + * better to call png_set_alpha_mode() with PNG_DEFAULT_sRGB than rely on the + * default if you don't know what the right answer is! + * + * The special value PNG_GAMMA_MAC_18 indicates an older Mac system (pre Mac OS + * 10.6) which used a correction table to implement a somewhat lower gamma on an + * otherwise sRGB system. + * + * Both these values are reserved (not simple gamma values) in order to allow + * more precise correction internally in the future. + * + * NOTE: the following values can be passed to either the fixed or floating + * point APIs, but the floating point API will also accept floating point + * values. + */ +#define PNG_DEFAULT_sRGB -1 /* sRGB gamma and color space */ +#define PNG_GAMMA_MAC_18 -2 /* Old Mac '1.8' gamma and color space */ +#define PNG_GAMMA_sRGB 220000 /* Television standards--matches sRGB gamma */ +#define PNG_GAMMA_LINEAR PNG_FP_1 /* Linear */ +#endif + +/* The following are examples of calls to png_set_alpha_mode to achieve the + * required overall gamma correction and, where necessary, alpha + * premultiplication. + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + * This is the default libpng handling of the alpha channel - it is not + * pre-multiplied into the color components. In addition the call states + * that the output is for a sRGB system and causes all PNG files without gAMA + * chunks to be assumed to be encoded using sRGB. + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + * In this case the output is assumed to be something like an sRGB conformant + * display preceeded by a power-law lookup table of power 1.45. This is how + * early Mac systems behaved. + * + * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR); + * This is the classic Jim Blinn approach and will work in academic + * environments where everything is done by the book. It has the shortcoming + * of assuming that input PNG data with no gamma information is linear - this + * is unlikely to be correct unless the PNG files where generated locally. + * Most of the time the output precision will be so low as to show + * significant banding in dark areas of the image. + * + * png_set_expand_16(pp); + * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_DEFAULT_sRGB); + * This is a somewhat more realistic Jim Blinn inspired approach. PNG files + * are assumed to have the sRGB encoding if not marked with a gamma value and + * the output is always 16 bits per component. This permits accurate scaling + * and processing of the data. If you know that your input PNG files were + * generated locally you might need to replace PNG_DEFAULT_sRGB with the + * correct value for your system. + * + * png_set_alpha_mode(pp, PNG_ALPHA_OPTIMIZED, PNG_DEFAULT_sRGB); + * If you just need to composite the PNG image onto an existing background + * and if you control the code that does this you can use the optimization + * setting. In this case you just copy completely opaque pixels to the + * output. For pixels that are not completely transparent (you just skip + * those) you do the composition math using png_composite or png_composite_16 + * below then encode the resultant 8-bit or 16-bit values to match the output + * encoding. + * + * Other cases + * If neither the PNG nor the standard linear encoding work for you because + * of the software or hardware you use then you have a big problem. The PNG + * case will probably result in halos around the image. The linear encoding + * will probably result in a washed out, too bright, image (it's actually too + * contrasty.) Try the ALPHA_OPTIMIZED mode above - this will probably + * substantially reduce the halos. Alternatively try: + * + * png_set_alpha_mode(pp, PNG_ALPHA_BROKEN, PNG_DEFAULT_sRGB); + * This option will also reduce the halos, but there will be slight dark + * halos round the opaque parts of the image where the background is light. + * In the OPTIMIZED mode the halos will be light halos where the background + * is dark. Take your pick - the halos are unavoidable unless you can get + * your hardware/software fixed! (The OPTIMIZED approach is slightly + * faster.) + * + * When the default gamma of PNG files doesn't match the output gamma. + * If you have PNG files with no gamma information png_set_alpha_mode allows + * you to provide a default gamma, but it also sets the ouput gamma to the + * matching value. If you know your PNG files have a gamma that doesn't + * match the output you can take advantage of the fact that + * png_set_alpha_mode always sets the output gamma but only sets the PNG + * default if it is not already set: + * + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_DEFAULT_sRGB); + * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); + * The first call sets both the default and the output gamma values, the + * second call overrides the output gamma without changing the default. This + * is easier than achieving the same effect with png_set_gamma. You must use + * PNG_ALPHA_PNG for the first call - internal checking in png_set_alpha will + * fire if more than one call to png_set_alpha_mode and png_set_background is + * made in the same read operation, however multiple calls with PNG_ALPHA_PNG + * are ignored. + */ #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED PNG_EXPORT(36, void, png_set_strip_alpha, (png_structp png_ptr)); @@ -1175,7 +1406,11 @@ PNG_EXPORT(46, void, png_set_invert_mono, (png_structp png_ptr)); #endif #ifdef PNG_READ_BACKGROUND_SUPPORTED -/* Handle alpha and tRNS by replacing with a background color. */ +/* Handle alpha and tRNS by replacing with a background color. Prior to + * libpng-1.5.4 this API must not be called before the PNG file header has been + * read. Doing so will result in unexpected behavior and possible warnings or + * errors if the PNG file contains a bKGD chunk. + */ PNG_FP_EXPORT(47, void, png_set_background, (png_structp png_ptr, png_const_color_16p background_color, int background_gamma_code, int need_expand, double background_gamma)); @@ -1190,7 +1425,13 @@ 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 +/* Scale a 16-bit depth file down to 8-bit, accurately. */ +PNG_EXPORT(229, void, png_set_scale_16, (png_structp png_ptr)); +#endif + +#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 @@ -1211,12 +1452,22 @@ PNG_EXPORT(49, void, png_set_quantize, */ #define PNG_GAMMA_THRESHOLD (PNG_GAMMA_THRESHOLD_FIXED*.00001) -/* Handle gamma correction. Screen_gamma=(display_exponent) */ +/* Handle gamma correction. Screen_gamma=(display_exponent). + * NOTE: this API simply sets the screen and file gamma values. It will + * therefore override the value for gamma in a PNG file if it is called after + * the file header has been read - use with care - call before reading the PNG + * file for best results! + * + * These routines accept the same gamma values as png_set_alpha_mode (described + * above). The PNG_GAMMA_ defines and PNG_DEFAULT_sRGB can be passed to either + * API (floating point or fixed.) Notice, however, that the 'file_gamma' value + * is the inverse of a 'screen gamma' value. + */ PNG_FP_EXPORT(50, void, png_set_gamma, (png_structp png_ptr, double screen_gamma, - double default_file_gamma)); + double override_file_gamma)); PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structp png_ptr, - png_fixed_point screen_gamma, png_fixed_point default_file_gamma)); + png_fixed_point screen_gamma, png_fixed_point override_file_gamma)); #endif #ifdef PNG_WRITE_FLUSH_SUPPORTED @@ -1391,6 +1642,7 @@ PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed, #define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ #define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ +#ifdef PNG_WRITE_SUPPORTED /* Set the library compression level. Currently, valid values range from * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 * (0 - no compression, 9 - "maximal" compression). Note that tests have @@ -1407,11 +1659,36 @@ PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structp png_ptr, PNG_EXPORT(71, void, png_set_compression_strategy, (png_structp png_ptr, int strategy)); +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structp png_ptr, int window_bits)); PNG_EXPORT(73, void, png_set_compression_method, (png_structp png_ptr, int method)); +#endif + +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +/* Also set zlib parameters for compressing non-IDAT chunks */ +PNG_EXPORT(222, void, png_set_text_compression_level, + (png_structp png_ptr, int level)); + +PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structp png_ptr, + int mem_level)); + +PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structp png_ptr, + int strategy)); + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +PNG_EXPORT(225, void, png_set_text_compression_window_bits, (png_structp + png_ptr, int window_bits)); + +PNG_EXPORT(226, void, png_set_text_compression_method, (png_structp png_ptr, + int method)); +#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ /* These next functions are called for input/output, memory, and error * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, @@ -1623,6 +1900,7 @@ PNG_EXPORTA(103, void, png_chunk_error, (png_structp png_ptr, PNG_EXPORTA(104, void, png_err, (png_structp png_ptr), PNG_NORETURN); #endif +#ifdef PNG_WARNINGS_SUPPORTED /* Non-fatal error in libpng. Can continue, but may have a problem. */ PNG_EXPORT(105, void, png_warning, (png_structp png_ptr, png_const_charp warning_message)); @@ -1630,6 +1908,7 @@ PNG_EXPORT(105, void, png_warning, (png_structp png_ptr, /* Non-fatal error in libpng, chunk name is prepended to message. */ PNG_EXPORT(106, void, png_chunk_warning, (png_structp png_ptr, png_const_charp warning_message)); +#endif #ifdef PNG_BENIGN_ERRORS_SUPPORTED /* Benign error in libpng. Can continue, but may have a problem. @@ -2297,7 +2576,7 @@ PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i)); * scripts/symbols.def as well. */ #ifdef PNG_EXPORT_LAST_ORDINAL - PNG_EXPORT_LAST_ORDINAL(221); + PNG_EXPORT_LAST_ORDINAL(229); #endif #ifdef __cplusplus diff --git a/src/libpng/pngconf.h b/src/libpng/pngconf.h index c82fa5866..222816e37 100644 --- a/src/libpng/pngconf.h +++ b/src/libpng/pngconf.h @@ -1,7 +1,7 @@ /* pngconf.h - machine configurable file for libpng * - * libpng version 1.5.2 - March 31, 2011 + * libpng version 1.5.4 - July 7, 2011 * * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) @@ -353,23 +353,6 @@ # ifndef PNG_NORETURN # define PNG_NORETURN __attribute__((__noreturn__)) # endif -# ifndef PNG_PTR_NORETURN - /* It's not enough to have the compiler be the correct compiler at - * this point - it's necessary for the library (which defines - * the type of the library longjmp) to also be the GNU library. - * This is because many systems use the GNU compiler with a - * non-GNU libc implementation. Min/GW headers are also compatible - * with GCC as well as uclibc, so it seems best to exclude known - * problem libcs here rather than just including known libcs. - * - * NOTE: this relies on the only use of PNG_PTR_NORETURN being with - * the system longjmp. If the same type is used elsewhere then this - * will need to be changed. - */ -# if !defined(__CYGWIN__) -# define PNG_PTR_NORETURN __attribute__((__noreturn__)) -# endif -# endif # ifndef PNG_ALLOCATED # define PNG_ALLOCATED __attribute__((__malloc__)) # endif @@ -382,9 +365,6 @@ # ifndef PNG_DEPRECATED # define PNG_DEPRECATED __attribute__((__deprecated__)) # endif -# ifndef PNG_DEPSTRUCT -# define PNG_DEPSTRUCT __attribute__((__deprecated__)) -# endif # ifndef PNG_PRIVATE # if 0 /* Doesn't work so we use deprecated instead*/ # define PNG_PRIVATE \ @@ -404,11 +384,10 @@ # ifndef PNG_NORETURN # define PNG_NORETURN __declspec(noreturn) # endif -# ifndef PNG_PTR_NORETURN -# define PNG_PTR_NORETURN /* not supported */ -# endif # ifndef PNG_ALLOCATED -# define PNG_ALLOCATED __declspec(restrict) +# if (_MSC_VER >= 1400) +# define PNG_ALLOCATED __declspec(restrict) +# endif # endif /* This specifically protects structure members that should only be @@ -419,9 +398,6 @@ # ifndef PNG_DEPRECATED # define PNG_DEPRECATED __declspec(deprecated) # endif -# ifndef PNG_DEPSTRUCT -# define PNG_DEPSTRUCT __declspec(deprecated) -# endif # ifndef PNG_PRIVATE # define PNG_PRIVATE __declspec(deprecated) # endif @@ -438,15 +414,9 @@ #ifndef PNG_NORETURN # define PNG_NORETURN /* This function does not return */ #endif -#ifndef PNG_PTR_NORETURN -# define PNG_PTR_NORETURN /* This function does not return */ -#endif #ifndef PNG_ALLOCATED # define PNG_ALLOCATED /* The result of the function is new memory */ #endif -#ifndef PNG_DEPSTRUCT -# define PNG_DEPSTRUCT /* Access to this struct member is deprecated */ -#endif #ifndef PNG_PRIVATE # define PNG_PRIVATE /* This is a private libpng function */ #endif diff --git a/src/libpng/pngerror.c b/src/libpng/pngerror.c index 8290bb410..4d4cebafa 100644 --- a/src/libpng/pngerror.c +++ b/src/libpng/pngerror.c @@ -1,7 +1,7 @@ /* pngerror.c - stub functions for i/o and memory allocation * - * Last changed in libpng 1.5.1 [February 3, 2011] + * Last changed in libpng 1.5.4 [July 7, 2011] * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -89,15 +89,121 @@ png_error,(png_structp png_ptr, png_const_charp error_message),PNG_NORETURN) PNG_FUNCTION(void,PNGAPI png_err,(png_structp png_ptr),PNG_NORETURN) { + /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed + * erroneously as '\0', instead of the empty string "". This was + * apparently an error, introduced in libpng-1.2.20, and png_default_error + * will crash in this case. + */ if (png_ptr != NULL && png_ptr->error_fn != NULL) - (*(png_ptr->error_fn))(png_ptr, '\0'); + (*(png_ptr->error_fn))(png_ptr, ""); /* If the custom handler doesn't exist, or if it returns, use the default handler, which will not return. */ - png_default_error(png_ptr, '\0'); + png_default_error(png_ptr, ""); } #endif /* PNG_ERROR_TEXT_SUPPORTED */ +/* Utility to safely appends strings to a buffer. This never errors out so + * error checking is not required in the caller. + */ +size_t +png_safecat(png_charp buffer, size_t bufsize, size_t pos, + png_const_charp string) +{ + if (buffer != NULL && pos < bufsize) + { + if (string != NULL) + while (*string != '\0' && pos < bufsize-1) + buffer[pos++] = *string++; + + buffer[pos] = '\0'; + } + + return pos; +} + +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED) +/* Utility to dump an unsigned value into a buffer, given a start pointer and + * and end pointer (which should point just *beyond* the end of the buffer!) + * Returns the pointer to the start of the formatted string. + */ +png_charp +png_format_number(png_const_charp start, png_charp end, int format, + png_alloc_size_t number) +{ + int count = 0; /* number of digits output */ + int mincount = 1; /* minimum number required */ + int output = 0; /* digit output (for the fixed point format) */ + + *--end = '\0'; + + /* This is written so that the loop always runs at least once, even with + * number zero. + */ + while (end > start && (number != 0 || count < mincount)) + { + + static const char digits[] = "0123456789ABCDEF"; + + switch (format) + { + case PNG_NUMBER_FORMAT_fixed: + /* Needs five digits (the fraction) */ + mincount = 5; + if (output || number % 10 != 0) + { + *--end = digits[number % 10]; + output = 1; + } + number /= 10; + break; + + case PNG_NUMBER_FORMAT_02u: + /* Expects at least 2 digits. */ + mincount = 2; + /* fall through */ + + case PNG_NUMBER_FORMAT_u: + *--end = digits[number % 10]; + number /= 10; + break; + + case PNG_NUMBER_FORMAT_02x: + /* This format expects at least two digits */ + mincount = 2; + /* fall through */ + + case PNG_NUMBER_FORMAT_x: + *--end = digits[number & 0xf]; + number >>= 4; + break; + + default: /* an error */ + number = 0; + break; + } + + /* Keep track of the number of digits added */ + ++count; + + /* Float a fixed number here: */ + if (format == PNG_NUMBER_FORMAT_fixed) if (count == 5) if (end > start) + { + /* End of the fraction, but maybe nothing was output? In that case + * drop the decimal point. If the number is a true zero handle that + * here. + */ + if (output) + *--end = '.'; + else if (number == 0) /* and !output */ + *--end = '0'; + } + } + + return end; +} +#endif + #ifdef PNG_WARNINGS_SUPPORTED /* This function is called whenever there is a non-fatal error. This function * should not be changed. If there is a need to handle warnings differently, @@ -128,6 +234,115 @@ png_warning(png_structp png_ptr, png_const_charp warning_message) else png_default_warning(png_ptr, warning_message + offset); } + +/* These functions support 'formatted' warning messages with up to + * PNG_WARNING_PARAMETER_COUNT parameters. In the format string the parameter + * is introduced by @, where 'number' starts at 1. This follows the + * standard established by X/Open for internationalizable error messages. + */ +void +png_warning_parameter(png_warning_parameters p, int number, + png_const_charp string) +{ + if (number > 0 && number <= PNG_WARNING_PARAMETER_COUNT) + (void)png_safecat(p[number-1], (sizeof p[number-1]), 0, string); +} + +void +png_warning_parameter_unsigned(png_warning_parameters p, int number, int format, + png_alloc_size_t value) +{ + char buffer[PNG_NUMBER_BUFFER_SIZE]; + png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value)); +} + +void +png_warning_parameter_signed(png_warning_parameters p, int number, int format, + png_int_32 value) +{ + png_alloc_size_t u; + png_charp str; + char buffer[PNG_NUMBER_BUFFER_SIZE]; + + /* Avoid overflow by doing the negate in a png_alloc_size_t: */ + u = (png_alloc_size_t)value; + if (value < 0) + u = ~u + 1; + + str = PNG_FORMAT_NUMBER(buffer, format, u); + + if (value < 0 && str > buffer) + *--str = '-'; + + png_warning_parameter(p, number, str); +} + +void +png_formatted_warning(png_structp png_ptr, png_warning_parameters p, + png_const_charp message) +{ + /* The internal buffer is just 128 bytes - enough for all our messages, + * overflow doesn't happen because this code checks! + */ + size_t i; + char msg[128]; + + for (i=0; i<(sizeof msg)-1 && *message != '\0'; ++i) + { + if (*message == '@') + { + int parameter = -1; + switch (*++message) + { + case '1': + parameter = 0; + break; + + case '2': + parameter = 1; + break; + + case '\0': + continue; /* To break out of the for loop above. */ + + default: + break; + } + + if (parameter >= 0 && parameter < PNG_WARNING_PARAMETER_COUNT) + { + /* Append this parameter */ + png_const_charp parm = p[parameter]; + png_const_charp pend = p[parameter] + (sizeof p[parameter]); + + /* No need to copy the trailing '\0' here, but there is no guarantee + * that parm[] has been initialized, so there is no guarantee of a + * trailing '\0': + */ + for (; i<(sizeof msg)-1 && parm != '\0' && parm < pend; ++i) + msg[i] = *parm++; + + ++message; + continue; + } + + /* else not a parameter and there is a character after the @ sign; just + * copy that. + */ + } + + /* At this point *message can't be '\0', even in the bad parameter case + * above where there is a lone '@' at the end of the message string. + */ + msg[i] = *message++; + } + + /* i is always less than (sizeof msg), so: */ + msg[i] = '\0'; + + /* And this is the formatted message: */ + png_warning(png_ptr, msg); +} #endif /* PNG_WARNINGS_SUPPORTED */ #ifdef PNG_BENIGN_ERRORS_SUPPORTED @@ -185,8 +400,13 @@ png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp { buffer[iout++] = ':'; buffer[iout++] = ' '; - png_memcpy(buffer + iout, error_message, PNG_MAX_ERROR_TEXT); - buffer[iout + PNG_MAX_ERROR_TEXT - 1] = '\0'; + + iin = 0; + while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\0') + buffer[iout++] = error_message[iin++]; + + /* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */ + buffer[iout] = '\0'; } } #endif /* PNG_WARNINGS_SUPPORTED || PNG_ERROR_TEXT_SUPPORTED */ @@ -272,7 +492,7 @@ png_set_longjmp_fn(png_structp png_ptr, png_longjmp_ptr longjmp_fn, return NULL; png_ptr->longjmp_fn = longjmp_fn; - return &png_ptr->png_jmpbuf; + return &png_ptr->longjmp_buffer; } #endif @@ -287,7 +507,8 @@ png_default_error,(png_structp png_ptr, png_const_charp error_message), { #ifdef PNG_CONSOLE_IO_SUPPORTED #ifdef PNG_ERROR_NUMBERS_SUPPORTED - if (*error_message == PNG_LITERAL_SHARP) + /* Check on NULL only added in 1.5.4 */ + if (error_message != NULL && *error_message == PNG_LITERAL_SHARP) { /* Strip "#nnnn " from beginning of error message. */ int offset; @@ -317,11 +538,11 @@ png_default_error,(png_structp png_ptr, png_const_charp error_message), else #endif { - fprintf(stderr, "libpng error: %s", error_message); + fprintf(stderr, "libpng error: %s", error_message ? error_message : + "undefined"); fprintf(stderr, PNG_STRING_NEWLINE); } -#endif -#ifndef PNG_CONSOLE_IO_SUPPORTED +#else PNG_UNUSED(error_message) /* Make compiler happy */ #endif png_longjmp(png_ptr, 1); @@ -335,13 +556,13 @@ png_longjmp,(png_structp png_ptr, int val),PNG_NORETURN) { # ifdef USE_FAR_KEYWORD { - jmp_buf png_jmpbuf; - png_memcpy(png_jmpbuf, png_ptr->png_jmpbuf, png_sizeof(jmp_buf)); - png_ptr->longjmp_fn(png_jmpbuf, val); + jmp_buf tmp_jmpbuf; + png_memcpy(tmp_jmpbuf, png_ptr->longjmp_buffer, png_sizeof(jmp_buf)); + png_ptr->longjmp_fn(tmp_jmpbuf, val); } # else - png_ptr->longjmp_fn(png_ptr->png_jmpbuf, val); + png_ptr->longjmp_fn(png_ptr->longjmp_buffer, val); # endif } #endif @@ -403,7 +624,7 @@ png_default_warning(png_structp png_ptr, png_const_charp warning_message) /* This function is called when the application wants to use another method * of handling errors and warnings. Note that the error function MUST NOT * return to the calling routine or serious problems will occur. The return - * method used in the default routine calls longjmp(png_ptr->png_jmpbuf, 1) + * method used in the default routine calls longjmp(png_ptr->longjmp_buffer, 1) */ void PNGAPI png_set_error_fn(png_structp png_ptr, png_voidp error_ptr, @@ -414,7 +635,11 @@ png_set_error_fn(png_structp png_ptr, png_voidp error_ptr, png_ptr->error_ptr = error_ptr; png_ptr->error_fn = error_fn; +#ifdef PNG_WARNINGS_SUPPORTED png_ptr->warning_fn = warning_fn; +#else + PNG_UNUSED(warning_fn) +#endif } diff --git a/src/libpng/pnginfo.h b/src/libpng/pnginfo.h index fa19f85e7..a33bfab06 100644 --- a/src/libpng/pnginfo.h +++ b/src/libpng/pnginfo.h @@ -138,7 +138,6 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) * single color specified that should be treated as fully transparent. * Data is valid if (valid & PNG_INFO_tRNS) is non-zero. */ - png_bytep trans; /* alpha values for paletted image */ png_bytep trans_alpha; /* alpha values for paletted image */ png_color_16 trans_color; /* transparent color for non-palette image */ #endif diff --git a/src/libpng/pnglibconf.h b/src/libpng/pnglibconf.h index a34b76660..ca7ea4610 100644 --- a/src/libpng/pnglibconf.h +++ b/src/libpng/pnglibconf.h @@ -1,6 +1,6 @@ /* pnglibconf.h - library build configuration */ -/* libpng version 1.5.0 - January 6, 2011 */ +/* libpng version 1.5.3 - July 7, 2011 */ /* Copyright (c) 1998-2011 Glenn Randers-Pehrson */ @@ -34,29 +34,31 @@ /* options */ #define PNG_WARNINGS_SUPPORTED #define PNG_INFO_IMAGE_SUPPORTED +#define PNG_TIME_RFC1123_SUPPORTED #define PNG_READ_SUPPORTED #define PNG_SETJMP_SUPPORTED #define PNG_READ_QUANTIZE_SUPPORTED #define PNG_HANDLE_AS_UNKNOWN_SUPPORTED #define PNG_POINTER_INDEXING_SUPPORTED -//#define PNG_MNG_FEATURES_SUPPORTED +/*#define PNG_MNG_FEATURES_SUPPORTED*/ #define PNG_INCH_CONVERSIONS_SUPPORTED #define PNG_IO_STATE_SUPPORTED #define PNG_FLOATING_ARITHMETIC_SUPPORTED +#define PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED #define PNG_FIXED_POINT_SUPPORTED #define PNG_WRITE_SUPPORTED /*#undef PNG_ERROR_NUMBERS_SUPPORTED*/ #define PNG_STDIO_SUPPORTED #define PNG_FLOATING_POINT_SUPPORTED -//#define PNG_PROGRESSIVE_READ_SUPPORTED +/*#define PNG_PROGRESSIVE_READ_SUPPORTED*/ #define PNG_READ_16BIT_SUPPORTED #define PNG_WRITE_INTERLACING_SUPPORTED #define PNG_READ_INT_FUNCTIONS_SUPPORTED #define PNG_READ_COMPOSITE_NODIV_SUPPORTED #define PNG_USER_LIMITS_SUPPORTED +#define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED #define PNG_SEQUENTIAL_READ_SUPPORTED #define PNG_CONSOLE_IO_SUPPORTED -/*#undef PNG_READ_16_TO_8_ACCURATE_SCALE_SUPPORTED*/ #define PNG_ALIGN_MEMORY_SUPPORTED #define PNG_BENIGN_ERRORS_SUPPORTED #define PNG_EASY_ACCESS_SUPPORTED @@ -70,15 +72,16 @@ #define PNG_ERROR_TEXT_SUPPORTED #define PNG_READ_pHYs_SUPPORTED #define PNG_WRITE_USER_TRANSFORM_SUPPORTED -#define PNG_READ_STRIP_ALPHA_SUPPORTED #define PNG_READ_OPT_PLTE_SUPPORTED +#define PNG_READ_ALPHA_MODE_SUPPORTED +#define PNG_WRITE_OPTIMIZE_CMF_SUPPORTED #define PNG_WRITE_16BIT_SUPPORTED #define PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED #define PNG_READ_oFFs_SUPPORTED -#define PNG_READ_16_TO_8_SUPPORTED #define PNG_READ_GRAY_TO_RGB_SUPPORTED #define PNG_READ_SWAP_SUPPORTED #define PNG_READ_SHIFT_SUPPORTED +#define PNG_READ_iTXt_SUPPORTED #define PNG_WRITE_INT_FUNCTIONS_SUPPORTED #define PNG_READ_PACKSWAP_SUPPORTED #define PNG_READ_USER_TRANSFORM_SUPPORTED @@ -88,16 +91,13 @@ #define PNG_WRITE_SWAP_SUPPORTED #define PNG_READ_UNKNOWN_CHUNKS_SUPPORTED #define PNG_READ_hIST_SUPPORTED -#define PNG_READ_TEXT_SUPPORTED #define PNG_WRITE_SWAP_ALPHA_SUPPORTED -#define PNG_TIME_RFC1123_SUPPORTED #define PNG_READ_cHRM_SUPPORTED #define PNG_READ_tRNS_SUPPORTED #define PNG_READ_BACKGROUND_SUPPORTED #define PNG_WRITE_INVERT_SUPPORTED #define PNG_WRITE_FLUSH_SUPPORTED #define PNG_READ_FILLER_SUPPORTED -#define PNG_READ_tEXt_SUPPORTED #define PNG_READ_pCAL_SUPPORTED #define PNG_READ_sPLT_SUPPORTED #define PNG_READ_SWAP_ALPHA_SUPPORTED @@ -105,6 +105,7 @@ #define PNG_WRITE_FILTER_SUPPORTED #define PNG_USER_TRANSFORM_INFO_SUPPORTED #define PNG_READ_INVERT_ALPHA_SUPPORTED +#define PNG_READ_SCALE_16_TO_8_SUPPORTED #define PNG_WRITE_ANCILLARY_CHUNKS_SUPPORTED #define PNG_WRITE_SHIFT_SUPPORTED #define PNG_READ_tIME_SUPPORTED @@ -125,50 +126,55 @@ #define PNG_WRITE_PACKSWAP_SUPPORTED #define PNG_READ_sBIT_SUPPORTED #define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED +#define PNG_WRITE_zTXt_SUPPORTED #define PNG_READ_iCCP_SUPPORTED #define PNG_READ_gAMA_SUPPORTED +#define PNG_READ_STRIP_16_TO_8_SUPPORTED #define PNG_READ_INVERT_SUPPORTED #define PNG_WRITE_sBIT_SUPPORTED +#define PNG_READ_STRIP_ALPHA_SUPPORTED #define PNG_READ_USER_CHUNKS_SUPPORTED #define PNG_WRITE_iCCP_SUPPORTED #define PNG_READ_EXPAND_SUPPORTED #define PNG_WRITE_sCAL_SUPPORTED #define PNG_WRITE_gAMA_SUPPORTED #define PNG_WRITE_pHYs_SUPPORTED -#define PNG_READ_iTXt_SUPPORTED #define PNG_WRITE_oFFs_SUPPORTED #define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED #define PNG_tIME_SUPPORTED +#define PNG_READ_COMPRESSED_TEXT_SUPPORTED #define PNG_USER_CHUNKS_SUPPORTED +#define PNG_WRITE_iTXt_SUPPORTED #define PNG_WRITE_bKGD_SUPPORTED #define PNG_WRITE_sRGB_SUPPORTED #define PNG_WRITE_hIST_SUPPORTED -#define PNG_WRITE_TEXT_SUPPORTED #define PNG_WRITE_cHRM_SUPPORTED #define PNG_WRITE_tRNS_SUPPORTED -#define PNG_WRITE_tEXt_SUPPORTED #define PNG_WRITE_pCAL_SUPPORTED #define PNG_WRITE_sPLT_SUPPORTED +#define PNG_zTXt_SUPPORTED #define PNG_sBIT_SUPPORTED #define PNG_iCCP_SUPPORTED #define PNG_gAMA_SUPPORTED #define PNG_sCAL_SUPPORTED #define PNG_pHYs_SUPPORTED +#define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED #define PNG_oFFs_SUPPORTED -#define PNG_WRITE_zTXt_SUPPORTED +#define PNG_iTXt_SUPPORTED #define PNG_bKGD_SUPPORTED #define PNG_sRGB_SUPPORTED -#define PNG_TEXT_SUPPORTED #define PNG_hIST_SUPPORTED #define PNG_cHRM_SUPPORTED #define PNG_tRNS_SUPPORTED -#define PNG_tEXt_SUPPORTED #define PNG_pCAL_SUPPORTED #define PNG_sPLT_SUPPORTED -#define PNG_WRITE_iTXt_SUPPORTED +#define PNG_READ_TEXT_SUPPORTED +#define PNG_READ_tEXt_SUPPORTED #define PNG_SAVE_INT_32_SUPPORTED #define PNG_CHECK_cHRM_SUPPORTED -#define PNG_zTXt_SUPPORTED -#define PNG_iTXt_SUPPORTED +#define PNG_WRITE_TEXT_SUPPORTED +#define PNG_WRITE_tEXt_SUPPORTED +#define PNG_TEXT_SUPPORTED +#define PNG_tEXt_SUPPORTED /* end of options */ #endif /* PNGLCONF_H */ diff --git a/src/libpng/pngmem.c b/src/libpng/pngmem.c index a15d8b085..ea606d6a6 100644 --- a/src/libpng/pngmem.c +++ b/src/libpng/pngmem.c @@ -1,7 +1,7 @@ /* pngmem.c - stub functions for memory allocation * - * Last changed in libpng 1.5.1 [February 3, 2011] + * Last changed in libpng 1.5.4 [July 7, 2011] * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -187,8 +187,9 @@ png_malloc_default,(png_structp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) int num_blocks; png_uint_32 total_size; png_bytep table; - int i; + int i, mem_level, window_bits; png_byte huge * hptr; + int window_bits if (ret != NULL) { @@ -196,14 +197,22 @@ png_malloc_default,(png_structp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) ret = NULL; } - if (png_ptr->zlib_window_bits > 14) - num_blocks = (int)(1 << (png_ptr->zlib_window_bits - 14)); + window_bits = + png_ptr->zlib_window_bits >= png_ptr->zlib_text_window_bits ? + png_ptr->zlib_window_bits : png_ptr->zlib_text_window_bits; + + if (window_bits > 14) + num_blocks = (int)(1 << (window_bits - 14)); else num_blocks = 1; - if (png_ptr->zlib_mem_level >= 7) - num_blocks += (int)(1 << (png_ptr->zlib_mem_level - 7)); + mem_level = + png_ptr->zlib_mem_level >= png_ptr->zlib_text_mem_level ? + png_ptr->zlib_mem_level : png_ptr->zlib_text_mem_level; + + if (mem_level >= 7) + num_blocks += (int)(1 << (mem_level - 7)); else num_blocks++; @@ -277,7 +286,7 @@ png_malloc_default,(png_structp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) { # ifndef PNG_USER_MEM_SUPPORTED if ((png_ptr->flags&PNG_FLAG_MALLOC_NULL_MEM_OK) == 0) - png_error(png_ptr, "Out of Memory"); /* Note "o" and "M" */ + png_error(png_ptr, "Out of Memory"); /* Note "O" and "M" */ else png_warning(png_ptr, "Out of Memory"); diff --git a/src/libpng/pngpread.c b/src/libpng/pngpread.c index 5ab9007a1..a50292a76 100644 --- a/src/libpng/pngpread.c +++ b/src/libpng/pngpread.c @@ -1026,8 +1026,10 @@ png_push_process_row(png_structp png_ptr) png_memcpy(png_ptr->prev_row, png_ptr->row_buf, png_ptr->rowbytes + 1); +#ifdef PNG_READ_TRANSFORMS_SUPPORTED if (png_ptr->transformations) png_do_read_transformations(png_ptr); +#endif #ifdef PNG_READ_INTERLACING_SUPPORTED /* Blow up interlaced rows to full size */ @@ -1288,7 +1290,7 @@ png_push_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 { PNG_UNUSED(info_ptr) /* To quiet some compiler warnings */ png_error(png_ptr, "Out of place tEXt"); - /*NOT REACHED*/ + /* NOT REACHED */ } #ifdef PNG_MAX_MALLOC_64K @@ -1385,7 +1387,7 @@ png_push_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 { PNG_UNUSED(info_ptr) /* To quiet some compiler warnings */ png_error(png_ptr, "Out of place zTXt"); - /*NOT REACHED*/ + /* NOT REACHED */ } #ifdef PNG_MAX_MALLOC_64K @@ -1589,7 +1591,7 @@ png_push_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 { PNG_UNUSED(info_ptr) /* To quiet some compiler warnings */ png_error(png_ptr, "Out of place iTXt"); - /*NOT REACHED*/ + /* NOT REACHED */ } #ifdef PNG_MAX_MALLOC_64K diff --git a/src/libpng/pngpriv.h b/src/libpng/pngpriv.h index a7e3b5272..5b4d2127c 100644 --- a/src/libpng/pngpriv.h +++ b/src/libpng/pngpriv.h @@ -6,7 +6,7 @@ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * - * Last changed in libpng 1.5.2 [March 31, 2011] + * Last changed in libpng 1.5.4 [July 7, 2011] * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -25,6 +25,20 @@ #ifndef PNGPRIV_H #define PNGPRIV_H +/* Feature Test Macros. The following are defined here to ensure that correctly + * implemented libraries reveal the APIs libpng needs to build and hide those + * that are not needed and potentially damaging to the compilation. + * + * Feature Test Macros must be defined before any system header is included (see + * POSIX 1003.1 2.8.2 "POSIX Symbols." + * + * These macros only have an effect if the operating system supports either + * POSIX 1003.1 or C99, or both. On other operating systems (particularly + * Windows/Visual Studio) there is no effect; the OS specific tests below are + * still required (as of 2011-05-02.) + */ +#define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ + /* This is required for the definition of abort(), used as a last ditch * error handler when all else fails. */ @@ -101,12 +115,27 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; # define PNG_ZBUF_SIZE 65536L #endif -/* If warnings or errors are turned off the code is disabled - * or redirected here. +/* 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_WARNINGS_SUPPORTED -# define png_warning(s1,s2) ((void)0) -# define png_chunk_warning(s1,s2) ((void)0) +#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. + */ +#ifdef PNG_WARNINGS_SUPPORTED +# define PNG_WARNING_PARAMETERS(p) png_warning_parameters p; +#else +# define png_warning(s1,s2) ((void)(s1)) +# define png_chunk_warning(s1,s2) ((void)(s1)) +# define png_warning_parameter(p,number,string) ((void)0) +# define png_warning_parameter_unsigned(p,number,format,value) ((void)0) +# define png_warning_parameter_signed(p,number,format,value) ((void)0) +# define png_formatted_warning(pp,p,message) ((void)(pp)) +# define PNG_WARNING_PARAMETERS(p) #endif #ifndef PNG_ERROR_TEXT_SUPPORTED # define png_error(s1,s2) png_err(s1) @@ -200,60 +229,28 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; # define NOCHECK 0 # define CVT_PTR(ptr) (png_far_to_near(png_ptr,ptr,CHECK)) # define CVT_PTR_NOCHECK(ptr) (png_far_to_near(png_ptr,ptr,NOCHECK)) -# define png_strcpy _fstrcpy -# define png_strncpy _fstrncpy /* Added to v 1.2.6 */ # define png_strlen _fstrlen # define png_memcmp _fmemcmp /* SJT: added */ # define png_memcpy _fmemcpy # define png_memset _fmemset -# define png_sprintf sprintf #else # ifdef _WINDOWS_ /* Favor Windows over C runtime fns */ # define CVT_PTR(ptr) (ptr) # define CVT_PTR_NOCHECK(ptr) (ptr) -# define png_strcpy lstrcpyA -# define png_strncpy lstrcpynA # define png_strlen lstrlenA # define png_memcmp memcmp # define png_memcpy CopyMemory # define png_memset memset -# define png_sprintf wsprintfA # else # define CVT_PTR(ptr) (ptr) # define CVT_PTR_NOCHECK(ptr) (ptr) -# define png_strcpy strcpy -# define png_strncpy strncpy /* Added to v 1.2.6 */ # define png_strlen strlen # define png_memcmp memcmp /* SJT: added */ # define png_memcpy memcpy # define png_memset memset -# define png_sprintf sprintf # endif #endif /* End of memory model/platform independent support */ - -#ifndef PNG_NO_SNPRINTF -# ifdef _MSC_VER -# define png_snprintf _snprintf /* Added to v 1.2.19 */ -# define png_snprintf2 _snprintf -# define png_snprintf6 _snprintf -# else -# define png_snprintf snprintf /* Added to v 1.2.19 */ -# define png_snprintf2 snprintf -# define png_snprintf6 snprintf -# endif -#else - /* You don't have or don't want to use snprintf(). Caution: Using - * sprintf instead of snprintf exposes your application to accidental - * or malevolent buffer overflows. If you don't have snprintf() - * as a general rule you should provide one (you can get one from - * Portable OpenSSH). - */ -# define png_snprintf(s1,n,fmt,x1) png_sprintf(s1,fmt,x1) -# define png_snprintf2(s1,n,fmt,x1,x2) png_sprintf(s1,fmt,x1,x2) -# define png_snprintf6(s1,n,fmt,x1,x2,x3,x4,x5,x6) \ - png_sprintf(s1,fmt,x1,x2,x3,x4,x5,x6) -#endif /* End of 1.5.0beta36 move from pngconf.h */ /* CONSTANTS and UTILITY MACROS @@ -261,12 +258,14 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; */ /* Various modes of operation. Note that after an init, mode is set to - * zero automatically when the structure is created. + * zero automatically when the structure is created. Three of these + * are defined in png.h because they need to be visible to applications + * that call png_set_unknown_chunk(). */ -#define PNG_HAVE_IHDR 0x01 -#define PNG_HAVE_PLTE 0x02 +/* #define PNG_HAVE_IHDR 0x01 (defined in png.h) */ +/* #define PNG_HAVE_PLTE 0x02 (defined in png.h) */ #define PNG_HAVE_IDAT 0x04 -#define PNG_AFTER_IDAT 0x08 /* Have complete zlib datastream */ +/* #define PNG_AFTER_IDAT 0x08 (defined in png.h) */ #define PNG_HAVE_IEND 0x10 #define PNG_HAVE_gAMA 0x20 #define PNG_HAVE_cHRM 0x40 @@ -286,10 +285,10 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; #define PNG_SWAP_BYTES 0x0010 #define PNG_INVERT_MONO 0x0020 #define PNG_QUANTIZE 0x0040 -#define PNG_BACKGROUND 0x0080 +#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 @@ -303,10 +302,10 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; #define PNG_RGB_TO_GRAY_ERR 0x200000L #define PNG_RGB_TO_GRAY_WARN 0x400000L #define PNG_RGB_TO_GRAY 0x600000L /* two bits, RGB_TO_GRAY_ERR|WARN */ - /* 0x800000L Unused */ +#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 */ - /* 0x4000000L unused */ +#define PNG_SCALE_16_TO_8 0x4000000L /* Added to libpng-1.5.4 */ /* 0x8000000L unused */ /* 0x10000000L unused */ /* 0x20000000L unused */ @@ -333,9 +332,9 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; #define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 #define PNG_FLAG_CRC_CRITICAL_USE 0x0400 #define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 - /* 0x1000 unused */ - /* 0x2000 unused */ - /* 0x4000 unused */ +#define PNG_FLAG_ASSUME_sRGB 0x1000 /* Added to libpng-1.5.4 */ +#define PNG_FLAG_OPTIMIZE_ALPHA 0x2000 /* Added to libpng-1.5.4 */ +#define PNG_FLAG_DETECT_UNINITIALIZED 0x4000 /* Added to libpng-1.5.4 */ #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000L #define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000L #define PNG_FLAG_LIBRARY_MISMATCH 0x20000L @@ -345,13 +344,13 @@ typedef PNG_CONST png_uint_16p FAR * png_const_uint_16pp; /* 0x200000L unused */ /* 0x400000L unused */ #define PNG_FLAG_BENIGN_ERRORS_WARN 0x800000L /* Added to libpng-1.4.0 */ - /* 0x1000000L unused */ - /* 0x2000000L unused */ - /* 0x4000000L unused */ - /* 0x8000000L unused */ - /* 0x10000000L unused */ - /* 0x20000000L unused */ - /* 0x40000000L unused */ +#define PNG_FLAG_ZTXT_CUSTOM_STRATEGY 0x1000000L /* 5 lines added */ +#define PNG_FLAG_ZTXT_CUSTOM_LEVEL 0x2000000L /* to libpng-1.5.4 */ +#define PNG_FLAG_ZTXT_CUSTOM_MEM_LEVEL 0x4000000L +#define PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS 0x8000000L +#define PNG_FLAG_ZTXT_CUSTOM_METHOD 0x10000000L + /* 0x20000000L unused */ + /* 0x40000000L unused */ #define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ PNG_FLAG_CRC_ANCILLARY_NOWARN) @@ -460,6 +459,11 @@ PNG_EXTERN png_fixed_point png_fixed PNGARG((png_structp png_ptr, double fp, #define PNG_tRNS PNG_CONST png_byte png_tRNS[5] = {116, 82, 78, 83, '\0'} #define PNG_zTXt PNG_CONST png_byte png_zTXt[5] = {122, 84, 88, 116, '\0'} +/* Gamma values (new at libpng-1.5.4): */ +#define PNG_GAMMA_MAC_OLD 151724 /* Assume '1.8' is really 2.2/1.45! */ +#define PNG_GAMMA_MAC_INVERSE 65909 +#define PNG_GAMMA_sRGB_INVERSE 45455 + /* Inhibit C++ name-mangling for libpng functions but not for system calls. */ #ifdef __cplusplus @@ -472,6 +476,12 @@ extern "C" { * be found in the files where the functions are located. */ +/* Check the user version string for compatibility, returns false if the version + * numbers aren't compatible. + */ +PNG_EXTERN int png_user_version_check(png_structp png_ptr, + png_const_charp user_png_ver); + /* Allocate memory for an internal libpng struct */ PNG_EXTERN PNG_FUNCTION(png_voidp,png_create_struct,PNGARG((int type)), PNG_ALLOCATED); @@ -540,8 +550,7 @@ PNG_EXTERN void png_crc_read PNGARG((png_structp png_ptr, png_bytep buf, png_size_t length)); /* Decompress data in a chunk that uses compression */ -#if defined(PNG_zTXt_SUPPORTED) || defined(PNG_iTXt_SUPPORTED) || \ - defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) +#if defined(PNG_READ_COMPRESSED_TEXT_SUPPORTED) PNG_EXTERN void png_decompress_chunk PNGARG((png_structp png_ptr, int comp_type, png_size_t chunklength, png_size_t prefix_length, png_size_t *data_length)); @@ -644,6 +653,7 @@ PNG_EXTERN void png_write_hIST PNGARG((png_structp png_ptr, png_const_uint_16p hist, int num_hist)); #endif +/* Chunks that have keywords */ #if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) PNG_EXTERN png_size_t png_check_keyword PNGARG((png_structp png_ptr, @@ -734,17 +744,17 @@ PNG_EXTERN void png_read_filter_row PNGARG((png_structp png_ptr, PNG_EXTERN void png_write_find_filter PNGARG((png_structp png_ptr, png_row_infop row_info)); -/* Write out the filtered row. */ -PNG_EXTERN void png_write_filtered_row PNGARG((png_structp png_ptr, - png_bytep filtered_row)); /* Finish a row while reading, dealing with interlacing passes, etc. */ PNG_EXTERN void png_read_finish_row PNGARG((png_structp png_ptr)); /* Initialize the row buffers, etc. */ PNG_EXTERN void png_read_start_row PNGARG((png_structp png_ptr)); + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED /* Optional call to update the users info structure */ PNG_EXTERN void png_read_transform_info PNGARG((png_structp png_ptr, png_infop info_ptr)); +#endif /* These are the functions that do the transformations */ #ifdef PNG_READ_FILLER_SUPPORTED @@ -816,7 +826,12 @@ PNG_EXTERN void png_do_invert PNGARG((png_row_infop row_info, png_bytep row)); #endif -#ifdef PNG_READ_16_TO_8_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 + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED PNG_EXTERN void png_do_chop PNGARG((png_row_infop row_info, png_bytep row)); #endif @@ -847,26 +862,20 @@ PNG_EXTERN void png_do_shift PNGARG((png_row_infop row_info, png_bytep row, png_const_color_8p bit_depth)); #endif -#ifdef PNG_READ_BACKGROUND_SUPPORTED -# ifdef PNG_READ_GAMMA_SUPPORTED -PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, - png_bytep row, png_const_color_16p trans_color, - png_const_color_16p background, png_const_color_16p background_1, - png_const_bytep gamma_table, png_const_bytep gamma_from_1, - png_const_bytep gamma_to_1, png_const_uint_16pp gamma_16, - png_const_uint_16pp gamma_16_from_1, png_const_uint_16pp gamma_16_to_1, - int gamma_shift)); -# else -PNG_EXTERN void png_do_background PNGARG((png_row_infop row_info, - png_bytep row, png_const_color_16p trans_color, - png_const_color_16p background)); -# endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) +PNG_EXTERN void png_do_compose PNGARG((png_row_infop row_info, + png_bytep row, png_structp png_ptr)); #endif #ifdef PNG_READ_GAMMA_SUPPORTED PNG_EXTERN void png_do_gamma PNGARG((png_row_infop row_info, - png_bytep row, png_const_bytep gamma_table, - png_const_uint_16pp gamma_16_table, int gamma_shift)); + png_bytep row, png_structp png_ptr)); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +PNG_EXTERN void png_do_encode_alpha PNGARG((png_row_infop row_info, + png_bytep row, png_structp png_ptr)); #endif #ifdef PNG_READ_EXPAND_SUPPORTED @@ -986,10 +995,16 @@ PNG_EXTERN void png_check_chunk_name PNGARG((png_structp png_ptr, png_const_bytep chunk_name)); /* Handle the transformations for reading and writing */ +#ifdef PNG_READ_TRANSFORMS_SUPPORTED PNG_EXTERN void png_do_read_transformations PNGARG((png_structp png_ptr)); +#endif +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED PNG_EXTERN void png_do_write_transformations PNGARG((png_structp png_ptr)); +#endif +#ifdef PNG_READ_TRANSFORMS_SUPPORTED PNG_EXTERN void png_init_read_transformations PNGARG((png_structp png_ptr)); +#endif #ifdef PNG_PROGRESSIVE_READ_SUPPORTED PNG_EXTERN void png_push_read_chunk PNGARG((png_structp png_ptr, @@ -1086,6 +1101,76 @@ PNG_EXTERN PNG_FUNCTION(void, png_fixed_error, (png_structp png_ptr, png_const_charp name),PNG_NORETURN); #endif +/* Puts 'string' into 'buffer' at buffer[pos], taking care never to overwrite + * the end. Always leaves the buffer nul terminated. Never errors out (and + * there is no error code.) + */ +PNG_EXTERN size_t png_safecat(png_charp buffer, size_t bufsize, size_t pos, + png_const_charp string); + +/* Various internal functions to handle formatted warning messages, currently + * only implemented for warnings. + */ +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED) +/* Utility to dump an unsigned value into a buffer, given a start pointer and + * and end pointer (which should point just *beyond* the end of the buffer!) + * Returns the pointer to the start of the formatted string. This utility only + * does unsigned values. + */ +PNG_EXTERN png_charp png_format_number(png_const_charp start, png_charp end, + int format, png_alloc_size_t number); + +/* Convenience macro that takes an array: */ +#define PNG_FORMAT_NUMBER(buffer,format,number) \ + png_format_number(buffer, buffer + (sizeof buffer), format, number) + +/* Suggested size for a number buffer (enough for 64 bits and a sign!) */ +#define PNG_NUMBER_BUFFER_SIZE 24 + +/* These are the integer formats currently supported, the name is formed from + * the standard printf(3) format string. + */ +#define PNG_NUMBER_FORMAT_u 1 /* chose unsigned API! */ +#define PNG_NUMBER_FORMAT_02u 2 +#define PNG_NUMBER_FORMAT_d 1 /* chose signed API! */ +#define PNG_NUMBER_FORMAT_02d 2 +#define PNG_NUMBER_FORMAT_x 3 +#define PNG_NUMBER_FORMAT_02x 4 +#define PNG_NUMBER_FORMAT_fixed 5 /* choose the signed API */ +#endif + +#ifdef PNG_WARNINGS_SUPPORTED +/* New defines and members adding in libpng-1.5.4 */ +# define PNG_WARNING_PARAMETER_SIZE 32 +# define PNG_WARNING_PARAMETER_COUNT 8 + +/* An l-value of this type has to be passed to the APIs below to cache the + * values of the parameters to a formatted warning message. + */ +typedef char png_warning_parameters[PNG_WARNING_PARAMETER_COUNT][ + PNG_WARNING_PARAMETER_SIZE]; + +PNG_EXTERN void png_warning_parameter(png_warning_parameters p, int number, + png_const_charp string); + /* Parameters are limited in size to PNG_WARNING_PARAMETER_SIZE characters, + * including the trailing '\0'. + */ +PNG_EXTERN void png_warning_parameter_unsigned(png_warning_parameters p, + int number, int format, png_alloc_size_t value); + /* Use png_alloc_size_t because it is an unsigned type as big as any we + * need to output. Use the following for a signed value. + */ +PNG_EXTERN void png_warning_parameter_signed(png_warning_parameters p, + int number, int format, png_int_32 value); + +PNG_EXTERN void png_formatted_warning(png_structp png_ptr, + png_warning_parameters p, png_const_charp message); + /* 'message' follows the X/Open approach of using @1, @2 to insert + * parameters previously supplied using the above functions. Errors in + * specifying the paramters will simple result in garbage substitutions. + */ +#endif + /* ASCII to FP interfaces, currently only implemented if sCAL * support is required. */ @@ -1148,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.) @@ -1157,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 @@ -1176,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/src/libpng/pngread.c b/src/libpng/pngread.c index aa84001c4..be3df4769 100644 --- a/src/libpng/pngread.c +++ b/src/libpng/pngread.c @@ -1,7 +1,7 @@ /* pngread.c - read a PNG file * - * Last changed in libpng 1.5.2 [March 31, 2011] + * Last changed in libpng 1.5.4 [July 7, 2011] * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -47,12 +47,10 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, #ifdef PNG_SETJMP_SUPPORTED #ifdef USE_FAR_KEYWORD - jmp_buf png_jmpbuf; + jmp_buf tmp_jmpbuf; #endif #endif - int i; - png_debug(1, "in png_create_read_struct"); #ifdef PNG_USER_MEM_SUPPORTED @@ -85,13 +83,13 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, encounter a png_error() will longjmp here. Since the jmpbuf is then meaningless we abort instead of returning. */ #ifdef USE_FAR_KEYWORD - if (setjmp(png_jmpbuf)) + if (setjmp(tmp_jmpbuf)) #else if (setjmp(png_jmpbuf(png_ptr))) /* Sets longjmp to match setjmp */ #endif PNG_ABORT(); #ifdef USE_FAR_KEYWORD - png_memcpy(png_jmpbuf(png_ptr), png_jmpbuf, png_sizeof(jmp_buf)); + png_memcpy(png_jmpbuf(png_ptr), tmp_jmpbuf, png_sizeof(jmp_buf)); #endif #endif /* PNG_SETJMP_SUPPORTED */ @@ -101,54 +99,9 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); - if (user_png_ver) - { - i = 0; - - do - { - if (user_png_ver[i] != png_libpng_ver[i]) - png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; - } while (png_libpng_ver[i++]); - } - - else - png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; - - - if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) - { - /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so - * we must recompile any applications that use any older library version. - * For versions after libpng 1.0, we will be compatible, so we need - * only check the first digit. - */ - if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || - (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || - (user_png_ver[0] == '0' && user_png_ver[2] < '9')) - { -#ifdef PNG_CONSOLE_IO_SUPPORTED - char msg[80]; - if (user_png_ver) - { - png_snprintf2(msg, 80, - "Application built with libpng-%.20s" - " but running with %.20s", - user_png_ver, - png_libpng_ver); - png_warning(png_ptr, msg); - } -#else - png_warning(png_ptr, - "Incompatible libpng version in application and library"); -#endif -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - png_ptr->flags = 0; -#endif - - png_cleanup_needed = 1; - } - } + /* Call the general version checker (shared with read and write code): */ + if (!png_user_version_check(png_ptr, user_png_ver)) + png_cleanup_needed = 1; if (!png_cleanup_needed) { @@ -457,7 +410,11 @@ png_read_update_info(png_structp png_ptr, png_infop info_ptr) "Ignoring extra png_read_update_info() call;" " row buffer not reallocated"); +#ifdef PNG_READ_TRANSFORMS_SUPPORTED png_read_transform_info(png_ptr, info_ptr); +#else + PNG_UNUSED(info_ptr) +#endif } #ifdef PNG_SEQUENTIAL_READ_SUPPORTED @@ -704,8 +661,10 @@ png_read_row(png_structp png_ptr, png_bytep row, png_bytep dsp_row) #endif +#ifdef PNG_READ_TRANSFORMS_SUPPORTED if (png_ptr->transformations) png_do_read_transformations(png_ptr); +#endif #ifdef PNG_READ_INTERLACING_SUPPORTED /* Blow up interlaced rows to full size */ @@ -1163,7 +1122,9 @@ png_read_destroy(png_structp png_ptr, png_infop info_ptr, jmp_buf tmp_jmp; #endif png_error_ptr error_fn; +#ifdef PNG_WARNINGS_SUPPORTED png_error_ptr warning_fn; +#endif png_voidp error_ptr; #ifdef PNG_USER_MEM_SUPPORTED png_free_ptr free_fn; @@ -1249,10 +1210,6 @@ png_read_destroy(png_structp png_ptr, png_infop info_ptr, #endif #endif -#ifdef PNG_TIME_RFC1123_SUPPORTED - png_free(png_ptr, png_ptr->time_buffer); -#endif - inflateEnd(&png_ptr->zstream); #ifdef PNG_PROGRESSIVE_READ_SUPPORTED @@ -1269,11 +1226,13 @@ png_read_destroy(png_structp png_ptr, png_infop info_ptr, * being used again. */ #ifdef PNG_SETJMP_SUPPORTED - png_memcpy(tmp_jmp, png_ptr->png_jmpbuf, png_sizeof(jmp_buf)); + png_memcpy(tmp_jmp, png_ptr->longjmp_buffer, png_sizeof(jmp_buf)); #endif error_fn = png_ptr->error_fn; +#ifdef PNG_WARNINGS_SUPPORTED warning_fn = png_ptr->warning_fn; +#endif error_ptr = png_ptr->error_ptr; #ifdef PNG_USER_MEM_SUPPORTED free_fn = png_ptr->free_fn; @@ -1282,14 +1241,16 @@ png_read_destroy(png_structp png_ptr, png_infop info_ptr, png_memset(png_ptr, 0, png_sizeof(png_struct)); png_ptr->error_fn = error_fn; +#ifdef PNG_WARNINGS_SUPPORTED png_ptr->warning_fn = warning_fn; +#endif png_ptr->error_ptr = error_ptr; #ifdef PNG_USER_MEM_SUPPORTED png_ptr->free_fn = free_fn; #endif #ifdef PNG_SETJMP_SUPPORTED - png_memcpy(png_ptr->png_jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); + png_memcpy(png_ptr->longjmp_buffer, tmp_jmp, png_sizeof(jmp_buf)); #endif } @@ -1325,8 +1286,22 @@ png_read_png(png_structp png_ptr, png_infop info_ptr, /* -------------- image transformations start here ------------------- */ -#ifdef PNG_READ_16_TO_8_SUPPORTED - /* Tell libpng to strip 16 bit/color files down to 8 bits per color. +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + /* Tell libpng to strip 16-bit/color files down to 8 bits per color. + */ + if (transforms & PNG_TRANSFORM_SCALE_16) + { + /* Added at libpng-1.5.4. "strip_16" produces the same result that it + * did in earlier versions, while "scale_16" is now more accurate. + */ + png_set_scale_16(png_ptr); + } +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + /* 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); @@ -1407,7 +1382,7 @@ png_read_png(png_structp png_ptr, png_infop info_ptr, #endif #ifdef PNG_READ_SWAP_SUPPORTED - /* Swap bytes of 16 bit files to least significant byte first */ + /* Swap bytes of 16-bit files to least significant byte first */ if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) png_set_swap(png_ptr); #endif @@ -1426,6 +1401,12 @@ png_read_png(png_structp png_ptr, png_infop info_ptr, png_set_gray_to_rgb(png_ptr); #endif +/* Added at libpng-1.5.4 */ +#ifdef PNG_READ_EXPAND_16_SUPPORTED + if (transforms & PNG_TRANSFORM_EXPAND_16) + png_set_expand_16(png_ptr); +#endif + /* We don't handle adding filler bytes */ /* We use png_read_image and rely on that for interlace handling, but we also diff --git a/src/libpng/pngrtran.c b/src/libpng/pngrtran.c index de5871add..4e0401aa9 100644 --- a/src/libpng/pngrtran.c +++ b/src/libpng/pngrtran.c @@ -1,7 +1,7 @@ /* pngrtran.c - transforms the data in a row for PNG readers * - * Last changed in libpng 1.5.2 [March 31, 2011] + * Last changed in libpng 1.5.4 [July 7, 2011] * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -106,12 +106,18 @@ png_set_background_fixed(png_structp png_ptr, return; } - png_ptr->transformations |= PNG_BACKGROUND; + png_ptr->transformations |= PNG_COMPOSE | PNG_STRIP_ALPHA; + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + png_memcpy(&(png_ptr->background), background_color, png_sizeof(png_color_16)); png_ptr->background_gamma = background_gamma; png_ptr->background_gamma_type = (png_byte)(background_gamma_code); - png_ptr->transformations |= (need_expand ? PNG_BACKGROUND_EXPAND : 0); + if (need_expand) + png_ptr->transformations |= PNG_BACKGROUND_EXPAND; + else + png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; } # ifdef PNG_FLOATING_POINT_SUPPORTED @@ -126,8 +132,25 @@ png_set_background(png_structp png_ptr, # endif /* FLOATING_POINT */ #endif /* READ_BACKGROUND */ -#ifdef PNG_READ_16_TO_8_SUPPORTED -/* Strip 16 bit depth files to 8 bit depth */ +/* 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) +{ + png_debug(1, "in png_set_scale_16"); + + if (png_ptr == NULL) + return; + + png_ptr->transformations |= PNG_SCALE_16_TO_8; +} +#endif + +#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) { @@ -137,7 +160,6 @@ png_set_strip_16(png_structp png_ptr) return; png_ptr->transformations |= PNG_16_TO_8; - png_ptr->transformations &= ~PNG_EXPAND_16; } #endif @@ -154,8 +176,190 @@ png_set_strip_alpha(png_structp png_ptr) } #endif +#if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED) +static png_fixed_point +translate_gamma_flags(png_structp png_ptr, png_fixed_point output_gamma, + int is_screen) +{ + /* Check for flag values. The main reason for having the old Mac value as a + * flag is that it is pretty near impossible to work out what the correct + * value is from Apple documentation - a working Mac system is needed to + * discover the value! + */ + if (output_gamma == PNG_DEFAULT_sRGB || + output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB) + { + /* If there is no sRGB support this just sets the gamma to the standard + * sRGB value. (This is a side effect of using this function!) + */ +# ifdef PNG_READ_sRGB_SUPPORTED + png_ptr->flags |= PNG_FLAG_ASSUME_sRGB; +# endif + if (is_screen) + output_gamma = PNG_GAMMA_sRGB; + else + output_gamma = PNG_GAMMA_sRGB_INVERSE; + } + + else if (output_gamma == PNG_GAMMA_MAC_18 || + output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18) + { + if (is_screen) + output_gamma = PNG_GAMMA_MAC_OLD; + else + output_gamma = PNG_GAMMA_MAC_INVERSE; + } + + return output_gamma; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +static png_fixed_point +convert_gamma_value(png_structp png_ptr, double output_gamma) +{ + /* The following silently ignores cases where fixed point (times 100,000) + * gamma values are passed to the floating point API. This is safe and it + * means the fixed point constants work just fine with the floating point + * API. The alternative would just lead to undetected errors and spurious + * bug reports. Negative values fail inside the _fixed API unless they + * correspond to the flag values. + */ + if (output_gamma > 0 && output_gamma < 128) + output_gamma *= PNG_FP_1; + + /* This preserves -1 and -2 exactly: */ + output_gamma = floor(output_gamma + .5); + + if (output_gamma > PNG_FP_MAX || output_gamma < PNG_FP_MIN) + png_fixed_error(png_ptr, "gamma value"); + + return (png_fixed_point)output_gamma; +} +# endif +#endif /* READ_ALPHA_MODE || READ_GAMMA */ + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +void PNGFAPI +png_set_alpha_mode_fixed(png_structp png_ptr, int mode, + png_fixed_point output_gamma) +{ + int compose = 0; + png_fixed_point file_gamma; + + png_debug(1, "in png_set_alpha_mode"); + + if (png_ptr == NULL) + return; + + output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/); + + /* Validate the value to ensure it is in a reasonable range. The value + * is expected to be 1 or greater, but this range test allows for some + * viewing correction values. The intent is to weed out users of this API + * who use the inverse of the gamma value accidentally! Since some of these + * values are reasonable this may have to be changed. + */ + if (output_gamma < 70000 || output_gamma > 300000) + png_error(png_ptr, "output gamma out of expected range"); + + /* The default file gamma is the inverse of the output gamma; the output + * gamma may be changed below so get the file value first: + */ + file_gamma = png_reciprocal(output_gamma); + + /* There are really 8 possibilities here, composed of any combination + * of: + * + * premultiply the color channels + * do not encode non-opaque pixels + * encode the alpha as well as the color channels + * + * The differences disappear if the input/output ('screen') gamma is 1.0, + * because then the encoding is a no-op and there is only the choice of + * premultiplying the color channels or not. + * + * png_set_alpha_mode and png_set_background interact because both use + * png_compose to do the work. Calling both is only useful when + * png_set_alpha_mode is used to set the default mode - PNG_ALPHA_PNG - along + * with a default gamma value. Otherwise PNG_COMPOSE must not be set. + */ + switch (mode) + { + case PNG_ALPHA_PNG: /* default: png standard */ + /* No compose, but it may be set by png_set_background! */ + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + break; + + case PNG_ALPHA_ASSOCIATED: /* color channels premultiplied */ + compose = 1; + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + /* The output is linear: */ + output_gamma = PNG_FP_1; + break; + + case PNG_ALPHA_OPTIMIZED: /* associated, non-opaque pixels linear */ + compose = 1; + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags |= PNG_FLAG_OPTIMIZE_ALPHA; + /* output_gamma records the encoding of opaque pixels! */ + break; + + case PNG_ALPHA_BROKEN: /* associated, non-linear, alpha encoded */ + compose = 1; + png_ptr->transformations |= PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + break; + + default: + png_error(png_ptr, "invalid alpha mode"); + } + + /* Only set the default gamma if the file gamma has not been set (this has + * the side effect that the gamma in a second call to png_set_alpha_mode will + * be ignored.) + */ + if (png_ptr->gamma == 0) + png_ptr->gamma = file_gamma; + + /* But always set the output gamma: */ + png_ptr->screen_gamma = output_gamma; + + /* Finally, if pre-multiplying, set the background fields to achieve the + * desired result. + */ + if (compose) + { + /* And obtain alpha pre-multiplication by composing on black: */ + png_memset(&png_ptr->background, 0, sizeof png_ptr->background); + png_ptr->background_gamma = png_ptr->gamma; /* just in case */ + png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE; + png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; + + if (png_ptr->transformations & PNG_COMPOSE) + png_error(png_ptr, + "conflicting calls to set alpha mode and background"); + + png_ptr->transformations |= PNG_COMPOSE; + } + + /* New API, make sure apps call the correct initializers: */ + png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED; +} + +# ifdef PNG_FLOATING_POINT_SUPPORTED +void PNGAPI +png_set_alpha_mode(png_structp png_ptr, int mode, double output_gamma) +{ + png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr, + output_gamma)); +} +# endif +#endif + #ifdef PNG_READ_QUANTIZE_SUPPORTED -/* Dither file to 8 bit. Supply a palette, the current number +/* Dither file to 8-bit. Supply a palette, the current number * of elements in the palette, the maximum number of elements * allowed, and a histogram if possible. If the current number * of colors is greater then the maximum number, the palette will be @@ -561,30 +765,6 @@ png_set_quantize(png_structp png_ptr, png_colorp palette, #endif /* PNG_READ_QUANTIZE_SUPPORTED */ #ifdef PNG_READ_GAMMA_SUPPORTED -/* Transform the image from the file_gamma to the screen_gamma. We - * only do transformations on images where the file_gamma and screen_gamma - * are not close reciprocals, otherwise it slows things down slightly, and - * also needlessly introduces small errors. - * - * We will turn off gamma transformation later if no semitransparent entries - * are present in the tRNS array for palette images. We can't do it here - * because we don't necessarily have the tRNS chunk yet. - */ -static int /* PRIVATE */ -png_gamma_threshold(png_fixed_point scrn_gamma, png_fixed_point file_gamma) -{ - /* PNG_GAMMA_THRESHOLD is the threshold for performing gamma - * correction as a difference of the overall transform from 1.0 - * - * We want to compare the threshold with s*f - 1, if we get - * overflow here it is because of wacky gamma values so we - * turn on processing anyway. - */ - png_fixed_point gtest; - return !png_muldiv(>est, scrn_gamma, file_gamma, PNG_FP_1) || - png_gamma_significant(gtest); -} - void PNGFAPI png_set_gamma_fixed(png_structp png_ptr, png_fixed_point scrn_gamma, png_fixed_point file_gamma) @@ -594,10 +774,32 @@ png_set_gamma_fixed(png_structp png_ptr, png_fixed_point scrn_gamma, if (png_ptr == NULL) return; - if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) || - (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || - png_gamma_threshold(scrn_gamma, file_gamma)) - png_ptr->transformations |= PNG_GAMMA; + /* New in libpng-1.5.4 - reserve particular negative values as flags. */ + scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/); + file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/); + +#if PNG_LIBPNG_VER >= 10600 + /* Checking the gamma values for being >0 was added in 1.5.4 along with the + * premultiplied alpha support; this actually hides an undocumented feature + * of the previous implementation which allowed gamma processing to be + * disabled in background handling. There is no evidence (so far) that this + * was being used; however, png_set_background itself accepted and must still + * accept '0' for the gamma value it takes, because it isn't always used. + * + * Since this is an API change (albeit a very minor one that removes an + * undocumented API feature) it will not be made until libpng-1.6.0. + */ + if (file_gamma <= 0) + png_error(png_ptr, "invalid file gamma in png_set_gamma"); + + if (scrn_gamma <= 0) + png_error(png_ptr, "invalid screen gamma in png_set_gamma"); +#endif + + /* Set the gamma values unconditionally - this overrides the value in the PNG + * file if a gAMA chunk was present. png_set_alpha_mode provides a + * different, easier, way to default the file gamma. + */ png_ptr->gamma = file_gamma; png_ptr->screen_gamma = scrn_gamma; } @@ -606,9 +808,8 @@ png_set_gamma_fixed(png_structp png_ptr, png_fixed_point scrn_gamma, void PNGAPI png_set_gamma(png_structp png_ptr, double scrn_gamma, double file_gamma) { - png_set_gamma_fixed(png_ptr, - png_fixed(png_ptr, scrn_gamma, "png_set_gamma screen gamma"), - png_fixed(png_ptr, file_gamma, "png_set_gamma file gamma")); + png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma), + convert_gamma_value(png_ptr, file_gamma)); } # endif /* FLOATING_POINT_SUPPORTED */ #endif /* READ_GAMMA */ @@ -688,7 +889,7 @@ png_set_tRNS_to_alpha(png_structp png_ptr) #endif /* defined(PNG_READ_EXPAND_SUPPORTED) */ #ifdef PNG_READ_EXPAND_16_SUPPORTED -/* Expand to 16 bit channels, expand the tRNS chunk too (because otherwise +/* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise * it may not work correctly.) */ void PNGAPI @@ -700,9 +901,10 @@ png_set_expand_16(png_structp png_ptr) return; png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS); - png_ptr->transformations &= ~PNG_16_TO_8; - png_ptr->flags &= ~PNG_FLAG_ROW_INIT; + + /* New API, make sure apps call the correct initializers: */ + png_ptr->flags |= PNG_FLAG_DETECT_UNINITIALIZED; } #endif @@ -762,30 +964,38 @@ png_set_rgb_to_gray_fixed(png_structp png_ptr, int error_action, } #endif { - png_uint_16 red_int, green_int; - if (red < 0 || green < 0) + if (red >= 0 && green >= 0 && red + green <= PNG_FP_1) { - red_int = 6968; /* .212671 * 32768 + .5 */ - green_int = 23434; /* .715160 * 32768 + .5 */ - } + png_uint_16 red_int, green_int; - else if (red + green < 100000L) - { red_int = (png_uint_16)(((png_uint_32)red*32768L)/100000L); green_int = (png_uint_16)(((png_uint_32)green*32768L)/100000L); + + png_ptr->rgb_to_gray_red_coeff = red_int; + png_ptr->rgb_to_gray_green_coeff = green_int; + png_ptr->rgb_to_gray_blue_coeff = + (png_uint_16)(32768 - red_int - green_int); } else { - png_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients"); - red_int = 6968; - green_int = 23434; - } + if (red >= 0 && green >= 0) + png_warning(png_ptr, + "ignoring out of range rgb_to_gray coefficients"); - png_ptr->rgb_to_gray_red_coeff = red_int; - png_ptr->rgb_to_gray_green_coeff = green_int; - png_ptr->rgb_to_gray_blue_coeff = - (png_uint_16)(32768 - red_int - green_int); + /* Use the defaults, from the cHRM chunk if set, else the built in Rec + * 709 values (which correspond to sRGB, so we don't have to worry + * about the sRGB chunk!) + */ + if (png_ptr->rgb_to_gray_red_coeff == 0 && + png_ptr->rgb_to_gray_green_coeff == 0 && + png_ptr->rgb_to_gray_blue_coeff == 0) + { + png_ptr->rgb_to_gray_red_coeff = 6968; /* .212671 * 32768 + .5 */ + png_ptr->rgb_to_gray_green_coeff = 23434; /* .715160 * 32768 + .5 */ + png_ptr->rgb_to_gray_blue_coeff = 2366; + } + } } } @@ -827,55 +1037,160 @@ png_set_read_user_transform_fn(png_structp png_ptr, png_user_transform_ptr } #endif +#ifdef PNG_READ_TRANSFORMS_SUPPORTED +#ifdef PNG_READ_GAMMA_SUPPORTED +/* In the case of gamma transformations only do transformations on images where + * the [file] gamma and screen_gamma are not close reciprocals, otherwise it + * slows things down slightly, and also needlessly introduces small errors. + */ +static int /* PRIVATE */ +png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma) +{ + /* PNG_GAMMA_THRESHOLD is the threshold for performing gamma + * correction as a difference of the overall transform from 1.0 + * + * We want to compare the threshold with s*f - 1, if we get + * overflow here it is because of wacky gamma values so we + * turn on processing anyway. + */ + png_fixed_point gtest; + return !png_muldiv(>est, screen_gamma, file_gamma, PNG_FP_1) || + png_gamma_significant(gtest); +} +#endif + /* Initialize everything needed for the read. This includes modifying * the palette. */ -void /* PRIVATE */ -png_init_read_transformations(png_structp png_ptr) -{ - png_debug(1, "in png_init_read_transformations"); - { -#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ - defined(PNG_READ_SHIFT_SUPPORTED) || \ - defined(PNG_READ_GAMMA_SUPPORTED) - int color_type = png_ptr->color_type; -#endif +/*For the moment 'png_init_palette_transformations' and + * 'png_init_rgb_transformations' only do some flag canceling optimizations. + * The intent is that these two routines should have palette or rgb operations + * extracted from 'png_init_read_transformations'. + */ +static void /* PRIVATE */ +png_init_palette_transformations(png_structp png_ptr) +{ + /* Called to handle the (input) palette case. In png_do_read_transformations + * the first step is to expand the palette if requested, so this code must + * take care to only make changes that are invariant with respect to the + * palette expansion, or only do them if there is no expansion. + * + * STRIP_ALPHA has already been handled in the caller (by setting num_trans + * to 0.) + */ + int input_has_alpha = 0; + int input_has_transparency = 0; + + if (png_ptr->num_trans > 0) + { + int i; + + /* Ignore if all the entries are opaque (unlikely!) */ + for (i=0; inum_trans; ++i) + if (png_ptr->trans_alpha[i] == 255) + continue; + else if (png_ptr->trans_alpha[i] == 0) + input_has_transparency = 1; + else + input_has_alpha = 1; + } + + /* If no alpha we can optimize. */ + if (!input_has_alpha) + { + /* Any alpha means background and associative alpha processing is + * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA + * and ENCODE_ALPHA are irrelevant. + */ + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + + if (!input_has_transparency) + png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); + } #if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /* Detect gray background and attempt to enable optimization - * for gray --> RGB case - * - * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or - * RGB_ALPHA (in which case need_expand is superfluous anyway), the - * background color might actually be gray yet not be flagged as such. - * This is not a problem for the current code, which uses - * PNG_BACKGROUND_IS_GRAY only to decide when to do the - * png_do_gray_to_rgb() transformation. + /* png_set_background handling - deals with the complexity of whether the + * background color is in the file format or the screen format in the case + * where an 'expand' will happen. */ - if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - !(color_type & PNG_COLOR_MASK_COLOR)) - { - png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; - } - - else if ((png_ptr->transformations & PNG_BACKGROUND) && - !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && - (png_ptr->transformations & PNG_GRAY_TO_RGB) && - png_ptr->background.red == png_ptr->background.green && - png_ptr->background.red == png_ptr->background.blue) - { - png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; - png_ptr->background.gray = png_ptr->background.red; - } -#endif + /* The following code cannot be entered in the alpha pre-multiplication case + * because PNG_BACKGROUND_EXPAND is cancelled below. + */ if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && (png_ptr->transformations & PNG_EXPAND)) { - if (!(color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */ + { + png_ptr->background.red = + png_ptr->palette[png_ptr->background.index].red; + png_ptr->background.green = + png_ptr->palette[png_ptr->background.index].green; + png_ptr->background.blue = + png_ptr->palette[png_ptr->background.index].blue; + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_ALPHA) + { + if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) + { + /* Invert the alpha channel (in tRNS) unless the pixels are + * going to be expanded, in which case leave it for later + */ + int i, istop = png_ptr->num_trans; + + for (i=0; itrans_alpha[i] = (png_byte)(255 - + png_ptr->trans_alpha[i]); + } + } +#endif /* PNG_READ_INVERT_ALPHA_SUPPORTED */ + } + } /* background expand and (therefore) no alpha association. */ +#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */ +} + +static void /* PRIVATE */ +png_init_rgb_transformations(png_structp png_ptr) +{ + /* Added to libpng-1.5.4: check the color type to determine whether there + * is any alpha or transparency in the image and simply cancel the + * background and alpha mode stuff if there isn't. + */ + int input_has_alpha = (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0; + int input_has_transparency = png_ptr->num_trans > 0; + + /* If no alpha we can optimize. */ + if (!input_has_alpha) + { + /* Any alpha means background and associative alpha processing is + * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA + * and ENCODE_ALPHA are irrelevant. + */ +# ifdef PNG_READ_ALPHA_MODE_SUPPORTED + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; +# endif + + if (!input_has_transparency) + png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); + } + +#if defined(PNG_READ_EXPAND_SUPPORTED) && defined(PNG_READ_BACKGROUND_SUPPORTED) + /* png_set_background handling - deals with the complexity of whether the + * background color is in the file format or the screen format in the case + * where an 'expand' will happen. + */ + + /* The following code cannot be entered in the alpha pre-multiplication case + * because PNG_BACKGROUND_EXPAND is cancelled below. + */ + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + (png_ptr->transformations & PNG_EXPAND) && + !(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) + /* i.e., GRAY or GRAY_ALPHA */ + { { /* Expand background and tRNS chunks */ switch (png_ptr->bit_depth) @@ -926,68 +1241,286 @@ png_init_read_transformations(png_structp png_ptr) break; } } - else if (color_type == PNG_COLOR_TYPE_PALETTE) - { - png_ptr->background.red = - png_ptr->palette[png_ptr->background.index].red; - png_ptr->background.green = - png_ptr->palette[png_ptr->background.index].green; - png_ptr->background.blue = - png_ptr->palette[png_ptr->background.index].blue; + } /* background expand and (therefore) no alpha association. */ +#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */ +} -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED - if (png_ptr->transformations & PNG_INVERT_ALPHA) - { -#ifdef PNG_READ_EXPAND_SUPPORTED - if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) -#endif - { - /* Invert the alpha channel (in tRNS) unless the pixels are - * going to be expanded, in which case leave it for later - */ - int i, istop; - istop=(int)png_ptr->num_trans; - for (i=0; itrans_alpha[i] = (png_byte)(255 - - png_ptr->trans_alpha[i]); - } - } -#endif +void /* PRIVATE */ +png_init_read_transformations(png_structp png_ptr) +{ + png_debug(1, "in png_init_read_transformations"); - } - } -#endif + /* This internal function is called from png_read_start_row in pngrutil.c + * and it is called before the 'rowbytes' calculation is done, so the code + * in here can change or update the transformations flags. + * + * First do updates that do not depend on the details of the PNG image data + * being processed. + */ -#if defined(PNG_READ_BACKGROUND_SUPPORTED) && defined(PNG_READ_GAMMA_SUPPORTED) - png_ptr->background_1 = png_ptr->background; -#endif #ifdef PNG_READ_GAMMA_SUPPORTED - - if ((color_type == PNG_COLOR_TYPE_PALETTE && png_ptr->num_trans != 0) - && png_gamma_threshold(png_ptr->screen_gamma, png_ptr->gamma)) + /* Prior to 1.5.4 these tests were performed from png_set_gamma, 1.5.4 adds + * png_set_alpha_mode and this is another source for a default file gamma so + * the test needs to be performed later - here. In addition prior to 1.5.4 + * the tests were repeated for the PALETTE color type here - this is no + * longer necessary (and doesn't seem to have been necessary before.) + */ { - int i, k; - k=0; - for (i=0; inum_trans; i++) + /* The following temporary indicates if overall gamma correction is + * required. + */ + int gamma_correction = 0; + + if (png_ptr->gamma != 0) /* has been set */ { - if (png_ptr->trans_alpha[i] != 0 && png_ptr->trans_alpha[i] != 0xff) - k=1; /* Partial transparency is present */ + if (png_ptr->screen_gamma != 0) /* screen set too */ + gamma_correction = png_gamma_threshold(png_ptr->gamma, + png_ptr->screen_gamma); + + else + /* Assume the output matches the input; a long time default behavior + * of libpng, although the standard has nothing to say about this. + */ + png_ptr->screen_gamma = png_reciprocal(png_ptr->gamma); } - if (k == 0) + + else if (png_ptr->screen_gamma != 0) + /* The converse - assume the file matches the screen, note that this + * perhaps undesireable default can (from 1.5.4) be changed by calling + * png_set_alpha_mode (even if the alpha handling mode isn't required + * or isn't changed from the default.) + */ + png_ptr->gamma = png_reciprocal(png_ptr->screen_gamma); + + else /* neither are set */ + /* Just in case the following prevents any processing - file and screen + * are both assumed to be linear and there is no way to introduce a + * third gamma value other than png_set_background with 'UNIQUE', and, + * prior to 1.5.4 + */ + png_ptr->screen_gamma = png_ptr->gamma = PNG_FP_1; + + /* Now turn the gamma transformation on or off as appropriate. Notice + * that PNG_GAMMA just refers to the file->screen correction. Alpha + * composition may independently cause gamma correction because it needs + * linear data (e.g. if the file has a gAMA chunk but the screen gamma + * hasn't been specified.) In any case this flag may get turned off in + * the code immediately below if the transform can be handled outside the + * row loop. + */ + if (gamma_correction) + png_ptr->transformations |= PNG_GAMMA; + + else png_ptr->transformations &= ~PNG_GAMMA; } +#endif - if ((png_ptr->transformations & (PNG_GAMMA | PNG_RGB_TO_GRAY)) && - png_ptr->gamma != 0) + /* Certain transformations have the effect of preventing other + * transformations that happen afterward in png_do_read_transformations, + * resolve the interdependencies here. From the code of + * png_do_read_transformations the order is: + * + * 1) PNG_EXPAND (including PNG_EXPAND_tRNS) + * 2) PNG_STRIP_ALPHA (if no compose) + * 3) PNG_RGB_TO_GRAY + * 4) PNG_GRAY_TO_RGB iff !PNG_BACKGROUND_IS_GRAY + * 5) PNG_COMPOSE + * 6) PNG_GAMMA + * 7) PNG_STRIP_ALPHA (if compose) + * 8) PNG_ENCODE_ALPHA + * 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) && + !(png_ptr->transformations & PNG_COMPOSE)) + { + /* Stripping the alpha channel happens immediately after the 'expand' + * transformations, before all other transformation, so it cancels out + * the alpha handling. It has the side effect negating the effect of + * PNG_EXPAND_tRNS too: + */ + png_ptr->transformations &= ~(PNG_BACKGROUND_EXPAND | PNG_ENCODE_ALPHA | + PNG_EXPAND_tRNS); + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + + /* Kill the tRNS chunk itself too. Prior to 1.5.4 this did not happen + * so transparency information would remain just so long as it wasn't + * expanded. This produces unexpected API changes if the set of things + * that do PNG_EXPAND_tRNS changes (perfectly possible given the + * documentation - which says ask for what you want, accept what you + * get.) This makes the behavior consistent from 1.5.4: + */ + png_ptr->num_trans = 0; + } +#endif /* STRIP_ALPHA supported, no COMPOSE */ + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + /* If the screen gamma is about 1.0 then the OPTIMIZE_ALPHA and ENCODE_ALPHA + * settings will have no effect. + */ + if (!png_gamma_significant(png_ptr->screen_gamma)) + { + png_ptr->transformations &= ~PNG_ENCODE_ALPHA; + png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; + } +#endif + +#if defined(PNG_READ_EXPAND_SUPPORTED) && \ + defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + defined(PNG_READ_GRAY_TO_RGB_SUPPORTED) + /* Detect gray background and attempt to enable optimization for + * gray --> RGB case. + * + * Note: if PNG_BACKGROUND_EXPAND is set and color_type is either RGB or + * RGB_ALPHA (in which case need_expand is superfluous anyway), the + * background color might actually be gray yet not be flagged as such. + * This is not a problem for the current code, which uses + * PNG_BACKGROUND_IS_GRAY only to decide when to do the + * png_do_gray_to_rgb() transformation. + * + * TODO: this code needs to be revised to avoid the complexity and + * interdependencies. The color type of the background should be recorded in + * png_set_background, along with the bit depth, then the code has a record + * of exactly what color space the background is currently in. + */ + if (png_ptr->transformations & PNG_BACKGROUND_EXPAND) + { + /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if + * the file was greyscale the background value is gray. + */ + if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) + png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; + } + + else if (png_ptr->transformations & PNG_COMPOSE) + { + /* PNG_COMPOSE: png_set_background was called with need_expand false, + * so the color is in the color space of the output or png_set_alpha_mode + * was called and the color is black. Ignore RGB_TO_GRAY because that + * happens before GRAY_TO_RGB. + */ + if (png_ptr->transformations & PNG_GRAY_TO_RGB) + { + if (png_ptr->background.red == png_ptr->background.green && + png_ptr->background.red == png_ptr->background.blue) + { + png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; + png_ptr->background.gray = png_ptr->background.red; + } + } + } +#endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED (etc) */ + + /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations + * can be performed directly on the palette, and some (such as rgb to gray) + * can be optimized inside the palette. This is particularly true of the + * composite (background and alpha) stuff, which can be pretty much all done + * in the palette even if the result is expanded to RGB or gray afterward. + * + * NOTE: this is Not Yet Implemented, the code behaves as in 1.5.1 and + * earlier and the palette stuff is actually handled on the first row. This + * leads to the reported bug that the palette returned by png_get_PLTE is not + * updated. + */ + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_init_palette_transformations(png_ptr); + + else + png_init_rgb_transformations(png_ptr); + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ + defined(PNG_READ_EXPAND_16_SUPPORTED) + if ((png_ptr->transformations & PNG_EXPAND_16) && + (png_ptr->transformations & PNG_COMPOSE) && + !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + png_ptr->bit_depth != 16) + { + /* TODO: fix this. Because the expand_16 operation is after the compose + * handling the background color must be 8, not 16, bits deep, but the + * application will supply a 16-bit value so reduce it here. + * + * The PNG_BACKGROUND_EXPAND code above does not expand to 16 bits at + * present, so that case is ok (until do_expand_16 is moved.) + * + * NOTE: this discards the low 16 bits of the user supplied background + * color, but until expand_16 works properly there is no choice! + */ +# define CHOP(x) (x)=((png_uint_16)(((png_uint_32)(x)*255+32895) >> 16)) + CHOP(png_ptr->background.red); + CHOP(png_ptr->background.green); + CHOP(png_ptr->background.blue); + CHOP(png_ptr->background.gray); +# undef CHOP + } +#endif /* PNG_READ_BACKGROUND_SUPPORTED && PNG_READ_EXPAND_16_SUPPORTED */ + + /* NOTE: below 'PNG_READ_ALPHA_MODE_SUPPORTED' is presumed to also enable the + * background support (see the comments in scripts/pnglibconf.dfa), this + * allows pre-multiplication of the alpha channel to be implemented as + * compositing on black. This is probably sub-optimal and has been done in + * 1.5.4 betas simply to enable external critique and testing (i.e. to + * implement the new API quickly, without lots of internal changes.) + */ + +#ifdef PNG_READ_GAMMA_SUPPORTED +# ifdef PNG_READ_BACKGROUND_SUPPORTED + /* Includes ALPHA_MODE */ + png_ptr->background_1 = png_ptr->background; +# endif + + /* This needs to change - in the palette image case a whole set of tables are + * built when it would be quicker to just calculate the correct value for + * each palette entry directly. Also, the test is too tricky - why check + * PNG_RGB_TO_GRAY if PNG_GAMMA is not set? The answer seems to be that + * PNG_GAMMA is cancelled even if the gamma is known? The test excludes the + * PNG_COMPOSE case, so apparently if there is no *overall* gamma correction + * the gamma tables will not be built even if composition is required on a + * gamma encoded value. + * + * In 1.5.4 this is addressed below by an additional check on the individual + * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the + * tables. + */ + if ((png_ptr->transformations & PNG_GAMMA) + || ((png_ptr->transformations & PNG_RGB_TO_GRAY) + && (png_gamma_significant(png_ptr->gamma) || + png_gamma_significant(png_ptr->screen_gamma))) + || ((png_ptr->transformations & PNG_COMPOSE) + && (png_gamma_significant(png_ptr->gamma) + || png_gamma_significant(png_ptr->screen_gamma) +# ifdef PNG_READ_BACKGROUND_SUPPORTED + || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE + && png_gamma_significant(png_ptr->background_gamma)) +# endif + )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) + && png_gamma_significant(png_ptr->screen_gamma)) + ) { png_build_gamma_table(png_ptr, png_ptr->bit_depth); #ifdef PNG_READ_BACKGROUND_SUPPORTED - if (png_ptr->transformations & PNG_BACKGROUND) + if (png_ptr->transformations & PNG_COMPOSE) { - if (color_type == PNG_COLOR_TYPE_PALETTE) + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - /* Could skip if no transparency */ + /* We don't get to here unless there is a tRNS chunk with non-opaque + * entries - see the checking code at the start of this function. + */ png_color back, back_1; png_colorp palette = png_ptr->palette; int num_palette = png_ptr->num_palette; @@ -1032,13 +1565,6 @@ png_init_read_transformations(png_structp png_ptr) } if (png_gamma_significant(gs)) - { - back.red = (png_byte)png_ptr->background.red; - back.green = (png_byte)png_ptr->background.green; - back.blue = (png_byte)png_ptr->background.blue; - } - - else { back.red = png_gamma_8bit_correct(png_ptr->background.red, gs); @@ -1047,12 +1573,32 @@ png_init_read_transformations(png_structp png_ptr) back.blue = png_gamma_8bit_correct(png_ptr->background.blue, gs); } - back_1.red = png_gamma_8bit_correct(png_ptr->background.red, g); - back_1.green = png_gamma_8bit_correct(png_ptr->background.green, - g); - back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue, - g); + + else + { + back.red = (png_byte)png_ptr->background.red; + back.green = (png_byte)png_ptr->background.green; + back.blue = (png_byte)png_ptr->background.blue; + } + + if (png_gamma_significant(g)) + { + back_1.red = png_gamma_8bit_correct(png_ptr->background.red, + g); + back_1.green = png_gamma_8bit_correct( + png_ptr->background.green, g); + back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue, + g); + } + + else + { + back_1.red = (png_byte)png_ptr->background.red; + back_1.green = (png_byte)png_ptr->background.green; + back_1.blue = (png_byte)png_ptr->background.blue; + } } + for (i = 0; i < num_palette; i++) { if (i < (int)png_ptr->num_trans && @@ -1086,19 +1632,18 @@ png_init_read_transformations(png_structp png_ptr) palette[i].blue = png_ptr->gamma_table[palette[i].blue]; } } - /* Prevent the transformations being done again, and make sure - * that the now spurious alpha channel is stripped - the code - * has just reduced background composition and gamma correction - * to a simple alpha channel strip. + + /* Prevent the transformations being done again. + * + * NOTE: this is highly dubious; it zaps the transformations in + * place. This seems inconsistent with the general treatment of the + * transformations elsewhere. */ - png_ptr->transformations &= ~PNG_BACKGROUND; - png_ptr->transformations &= ~PNG_GAMMA; - png_ptr->transformations |= PNG_STRIP_ALPHA; - } + png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA); + } /* color_type == PNG_COLOR_TYPE_PALETTE */ /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */ - else - /* color_type != PNG_COLOR_TYPE_PALETTE */ + else /* color_type != PNG_COLOR_TYPE_PALETTE */ { png_fixed_point g = PNG_FP_1; png_fixed_point gs = PNG_FP_1; @@ -1164,17 +1709,21 @@ png_init_read_transformations(png_structp png_ptr) png_ptr->background.red = png_ptr->background.green = png_ptr->background.blue = png_ptr->background.gray; } - } - } + } /* color_type != PNG_COLOR_TYPE_PALETTE */ + }/* png_ptr->transformations & PNG_BACKGROUND */ + else /* Transformation does not include PNG_BACKGROUND */ #endif /* PNG_READ_BACKGROUND_SUPPORTED */ - if (color_type == PNG_COLOR_TYPE_PALETTE) + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { png_colorp palette = png_ptr->palette; int num_palette = png_ptr->num_palette; int i; + /*NOTE: there are other transformations that should probably be in here + * too. + */ for (i = 0; i < num_palette; i++) { palette[i].red = png_ptr->gamma_table[palette[i].red]; @@ -1184,16 +1733,17 @@ png_init_read_transformations(png_structp png_ptr) /* Done the gamma correction. */ png_ptr->transformations &= ~PNG_GAMMA; - } + } /* color_type == PALETTE && !PNG_BACKGROUND transformation */ } #ifdef PNG_READ_BACKGROUND_SUPPORTED else #endif #endif /* PNG_READ_GAMMA_SUPPORTED */ + #ifdef PNG_READ_BACKGROUND_SUPPORTED - /* No GAMMA transformation */ - if ((png_ptr->transformations & PNG_BACKGROUND) && - (color_type == PNG_COLOR_TYPE_PALETTE)) + /* No GAMMA transformation (see the hanging else 4 lines above) */ + if ((png_ptr->transformations & PNG_COMPOSE) && + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) { int i; int istop = (int)png_ptr->num_trans; @@ -1225,15 +1775,13 @@ png_init_read_transformations(png_structp png_ptr) } } - /* Handled alpha, still need to strip the channel. */ - png_ptr->transformations &= ~PNG_BACKGROUND; - png_ptr->transformations |= PNG_STRIP_ALPHA; + png_ptr->transformations &= ~PNG_COMPOSE; } #endif /* PNG_READ_BACKGROUND_SUPPORTED */ #ifdef PNG_READ_SHIFT_SUPPORTED if ((png_ptr->transformations & PNG_SHIFT) && - (color_type == PNG_COLOR_TYPE_PALETTE)) + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) { png_uint_16 i; png_uint_16 istop = png_ptr->num_palette; @@ -1258,12 +1806,6 @@ png_init_read_transformations(png_structp png_ptr) } } #endif /* PNG_READ_SHIFT_SUPPORTED */ - } -#if !defined(PNG_READ_GAMMA_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) \ - && !defined(PNG_READ_BACKGROUND_SUPPORTED) - if (png_ptr) - return; -#endif } /* Modify the info structure to reflect the transformations. The @@ -1280,8 +1822,11 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr) { if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - if (png_ptr->num_trans && - (png_ptr->transformations & PNG_EXPAND_tRNS)) + /* This check must match what actually happens in + * png_do_expand_palette; if it ever checks the tRNS chunk to see if + * it is all opaque we must do the same (at present it does not.) + */ + if (png_ptr->num_trans > 0) info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA; else @@ -1305,44 +1850,61 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr) } #endif -#ifdef PNG_READ_EXPAND_16_SUPPORTED - if (png_ptr->transformations & PNG_EXPAND_16 && info_ptr->bit_depth == 8 && - info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) - { - info_ptr->bit_depth = 16; - } -#endif - -#ifdef PNG_READ_BACKGROUND_SUPPORTED - if (png_ptr->transformations & PNG_BACKGROUND) - { - info_ptr->color_type = (png_byte)(info_ptr->color_type & - ~PNG_COLOR_MASK_ALPHA); - info_ptr->num_trans = 0; +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + /* The following is almost certainly wrong unless the background value is in + * the screen space! + */ + if (png_ptr->transformations & PNG_COMPOSE) info_ptr->background = png_ptr->background; - } #endif #ifdef PNG_READ_GAMMA_SUPPORTED - if (png_ptr->transformations & PNG_GAMMA) - { - info_ptr->gamma = png_ptr->gamma; - } + /* The following used to be conditional on PNG_GAMMA (prior to 1.5.4), + * however it seems that the code in png_init_read_transformations, which has + * been called before this from png_read_update_info->png_read_start_row + * sometimes does the gamma transform and cancels the flag. + */ + 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) && (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) { - png_ptr->transformations |=PNG_16_TO_8; - info_ptr->bit_depth = 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 +#endif /* !READ_16BIT_SUPPORTED */ } -#endif -#endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED if (png_ptr->transformations & PNG_GRAY_TO_RGB) @@ -1366,6 +1928,14 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr) } #endif +#ifdef PNG_READ_EXPAND_16_SUPPORTED + if (png_ptr->transformations & PNG_EXPAND_16 && info_ptr->bit_depth == 8 && + info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + { + info_ptr->bit_depth = 16; + } +#endif + #ifdef PNG_READ_PACK_SUPPORTED if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8)) info_ptr->bit_depth = 8; @@ -1382,7 +1952,10 @@ png_read_transform_info(png_structp png_ptr, png_infop info_ptr) #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED if (png_ptr->transformations & PNG_STRIP_ALPHA) + { info_ptr->color_type &= ~PNG_COLOR_MASK_ALPHA; + info_ptr->num_trans = 0; + } #endif if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) @@ -1418,6 +1991,14 @@ defined(PNG_READ_USER_TRANSFORM_SUPPORTED) info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, info_ptr->width); + /* Adding in 1.5.4: cache the above value in png_struct so that we can later + * check in png_rowbytes that the user buffer won't get overwritten. Note + * that the field is not always set - if png_read_update_info isn't called + * the application has to either not do any transforms or get the calculation + * right itself. + */ + png_ptr->info_rowbytes = info_ptr->rowbytes; + #ifndef PNG_READ_EXPAND_SUPPORTED if (png_ptr) return; @@ -1435,29 +2016,27 @@ png_do_read_transformations(png_structp png_ptr) if (png_ptr->row_buf == NULL) { -#ifdef PNG_CONSOLE_IO_SUPPORTED - char msg[50]; - - png_snprintf2(msg, 50, - "NULL row buffer for row %ld, pass %d", (long)png_ptr->row_number, - png_ptr->pass); - png_error(png_ptr, msg); -#else - png_error(png_ptr, "NULL row buffer"); -#endif - } -#ifdef PNG_WARN_UNINITIALIZED_ROW - if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) - /* Application has failed to call either png_read_start_image() - * or png_read_update_info() after setting transforms that expand - * pixels. This check added to libpng-1.2.19 + /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this + * error is incredibly rare and incredibly easy to debug without this + * information. + */ + png_error(png_ptr, "NULL row buffer"); + } + + /* The following is debugging; prior to 1.5.4 the code was never compiled in; + * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro + * PNG_WARN_UNINITIALIZED_ROW removed. In 1.5 the new flag is set only for + * selected new APIs to ensure that there is no API change. + */ + if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 && + !(png_ptr->flags & PNG_FLAG_ROW_INIT)) + { + /* Application has failed to call either png_read_start_image() or + * png_read_update_info() after setting transforms that expand pixels. + * This check added to libpng-1.2.19 (but not enabled until 1.5.4). */ -#if (PNG_WARN_UNINITIALIZED_ROW==1) png_error(png_ptr, "Uninitialized row"); -#else - png_warning(png_ptr, "Uninitialized row"); -#endif -#endif + } #ifdef PNG_READ_EXPAND_SUPPORTED if (png_ptr->transformations & PNG_EXPAND) @@ -1482,16 +2061,13 @@ png_do_read_transformations(png_structp png_ptr) } #endif - /* Delay the 'expand 16' step until later for efficiency, so that the - * intermediate steps work with 8 bit data. - */ - #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED if ((png_ptr->transformations & PNG_STRIP_ALPHA) && + !(png_ptr->transformations & PNG_COMPOSE) && (png_ptr->row_info.color_type == PNG_COLOR_TYPE_RGB_ALPHA || png_ptr->row_info.color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) png_do_strip_channel(&(png_ptr->row_info), png_ptr->row_buf + 1, - 0/*!at_start, because SWAP_ALPHA happens later*/); + 0 /* at_start == false, because SWAP_ALPHA happens later */); #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED @@ -1555,36 +2131,49 @@ png_do_read_transformations(png_structp png_ptr) png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); #endif -#ifdef PNG_READ_BACKGROUND_SUPPORTED - if ((png_ptr->transformations & PNG_BACKGROUND) && - ((png_ptr->num_trans != 0) || - (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) - png_do_background(&(png_ptr->row_info), png_ptr->row_buf + 1, - &(png_ptr->trans_color), &(png_ptr->background) -#ifdef PNG_READ_GAMMA_SUPPORTED - , &(png_ptr->background_1), - png_ptr->gamma_table, png_ptr->gamma_from_1, - png_ptr->gamma_to_1, png_ptr->gamma_16_table, - png_ptr->gamma_16_from_1, png_ptr->gamma_16_to_1, - png_ptr->gamma_shift -#endif - ); +#if (defined PNG_READ_BACKGROUND_SUPPORTED) ||\ + (defined PNG_READ_ALPHA_MODE_SUPPORTED) + if (png_ptr->transformations & PNG_COMPOSE) + png_do_compose(&(png_ptr->row_info), png_ptr->row_buf + 1, png_ptr); #endif #ifdef PNG_READ_GAMMA_SUPPORTED if ((png_ptr->transformations & PNG_GAMMA) && -#ifdef PNG_READ_BACKGROUND_SUPPORTED - !((png_ptr->transformations & PNG_BACKGROUND) && +#if (defined PNG_READ_BACKGROUND_SUPPORTED) ||\ + (defined PNG_READ_ALPHA_MODE_SUPPORTED) + !((png_ptr->transformations & PNG_COMPOSE) && ((png_ptr->num_trans != 0) || (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) && #endif (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) - png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1, - png_ptr->gamma_table, png_ptr->gamma_16_table, - png_ptr->gamma_shift); + png_do_gamma(&(png_ptr->row_info), png_ptr->row_buf + 1, png_ptr); #endif -#ifdef PNG_READ_16_TO_8_SUPPORTED +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) && + (png_ptr->transformations & PNG_COMPOSE) && + (png_ptr->row_info.color_type == PNG_COLOR_TYPE_RGB_ALPHA || + png_ptr->row_info.color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + png_do_strip_channel(&(png_ptr->row_info), png_ptr->row_buf + 1, + 0 /* at_start == false, because SWAP_ALPHA happens later */); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + if ((png_ptr->transformations & PNG_ENCODE_ALPHA) && + (png_ptr->row_info.color_type & PNG_COLOR_MASK_ALPHA)) + png_do_encode_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + 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 @@ -1610,6 +2199,13 @@ png_do_read_transformations(png_structp png_ptr) png_do_expand_16(&png_ptr->row_info, png_ptr->row_buf + 1); #endif +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /*NOTE: moved here in 1.5.4 (from much later in this list.) */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) + png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); +#endif + #ifdef PNG_READ_INVERT_SUPPORTED if (png_ptr->transformations & PNG_INVERT_MONO) png_do_invert(&(png_ptr->row_info), png_ptr->row_buf + 1); @@ -1636,16 +2232,6 @@ png_do_read_transformations(png_structp png_ptr) png_do_packswap(&(png_ptr->row_info), png_ptr->row_buf + 1); #endif -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /*NOTE: this must be in the wrong place - what happens if BGR is set too? - * Need pngvalid to test this combo. - */ - /* If gray -> RGB, do so now only if we did not do so above */ - if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && - (png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) - png_do_gray_to_rgb(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - #ifdef PNG_READ_FILLER_SUPPORTED if (png_ptr->transformations & PNG_FILLER) png_do_read_filler(&(png_ptr->row_info), png_ptr->row_buf + 1, @@ -1697,7 +2283,6 @@ png_do_read_transformations(png_structp png_ptr) png_ptr->row_info.width); } #endif - } #ifdef PNG_READ_PACK_SUPPORTED @@ -1919,54 +2504,86 @@ png_do_unshift(png_row_infop row_info, png_bytep row, } #endif -#ifdef PNG_READ_16_TO_8_SUPPORTED -/* Chop rows of bit depth 16 down to 8 */ +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +/* Scale rows of bit depth 16 down to 8 accurately */ void /* PRIVATE */ +png_do_scale_16_to_8(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_scale_16_to_8"); + + if (row_info->bit_depth == 16) + { + png_bytep sp = row; /* source */ + png_bytep dp = row; /* destinaton */ + png_bytep ep = sp + row_info->rowbytes; /* end+1 */ + + while (sp < ep) + { + /* The input is an array of 16 bit components, these must be scaled to + * 8 bits each. For a 16 bit value V the required value (from the PNG + * specification) is: + * + * (V * 255) / 65535 + * + * This reduces to round(V / 257), or floor((V + 128.5)/257) + * + * Represent V as the two byte value vhi.vlo. Make a guess that the + * result is the top byte of V, vhi, then the correction to this value + * is: + * + * error = floor(((V-vhi.vhi) + 128.5) / 257) + * = floor(((vlo-vhi) + 128.5) / 257) + * + * This can be approximated using integer arithmetic (and a signed + * shift): + * + * error = (vlo-vhi+128) >> 8; + * + * The approximate differs from the exact answer only when (vlo-vhi) is + * 128; it then gives a correction of +1 when the exact correction is + * 0. This gives 128 errors. The exact answer (correct for all 16 bit + * input values) is: + * + * error = (vlo-vhi+128)*65535 >> 24; + * + * An alternative arithmetic calculation which also gives no errors is: + * + * (V * 255 + 32895) >> 16 + */ + + png_int_32 tmp = *sp++; /* must be signed! */ + tmp += (((int)*sp++ - tmp + 128) * 65535) >> 24; + *dp++ = (png_byte)tmp; + } + + row_info->bit_depth = 8; + row_info->pixel_depth = (png_byte)(8 * row_info->channels); + row_info->rowbytes = row_info->width * row_info->channels; + } +} +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +void /* PRIVATE */ +/* Simply discard the low byte. This was the default behavior prior + * to libpng-1.5.4. + */ png_do_chop(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_chop"); if (row_info->bit_depth == 16) { - png_bytep sp = row; - png_bytep dp = row; - png_uint_32 i; - png_uint_32 istop = row_info->width * row_info->channels; + png_bytep sp = row; /* source */ + png_bytep dp = row; /* destinaton */ + png_bytep ep = sp + row_info->rowbytes; /* end+1 */ - for (i = 0; i> 8)) >> 8; - * - * Approximate calculation with shift/add instead of multiply/divide: - * *dp = ((((png_uint_32)(*sp) << 8) | - * (png_uint_32)((int)(*(sp + 1)) - *sp)) + 128) >> 8; - * - * What we actually do to avoid extra shifting and conversion: - */ - - *dp = *sp + ((((int)(*(sp + 1)) - *sp) > 128) ? 1 : 0); -#else - /* Simply discard the low order byte */ - *dp = *sp; -#endif + *dp++ = *sp; + sp += 2; /* skip low byte */ } + row_info->bit_depth = 8; row_info->pixel_depth = (png_byte)(8 * row_info->channels); row_info->rowbytes = row_info->width * row_info->channels; @@ -2721,11 +3338,13 @@ png_do_rgb_to_gray(png_structp png_ptr, png_row_infop row_info, png_bytep row) return rgb_error; } #endif +#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ +#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED /* Build a grayscale palette. Palette is assumed to be 1 << bit_depth * large of png_color. This lets grayscale images be treated as * paletted. Most useful for gamma correction and simplification - * of code. + * of code. This API is not used internally. */ void PNGAPI png_build_grayscale_palette(int bit_depth, png_colorp palette) @@ -2775,34 +3394,36 @@ png_build_grayscale_palette(int bit_depth, png_colorp palette) palette[i].blue = (png_byte)v; } } +#endif +#ifdef PNG_READ_TRANSFORMS_SUPPORTED #ifdef PNG_READ_BACKGROUND_SUPPORTED /* Replace any alpha or transparency with the supplied background color. * "background" is already in the screen gamma, while "background_1" is * at a gamma of 1.0. Paletted files have already been taken care of. */ void /* PRIVATE */ -png_do_background(png_row_infop row_info, png_bytep row, - png_const_color_16p trans_color, png_const_color_16p background -#ifdef PNG_READ_GAMMA_SUPPORTED - , png_const_color_16p background_1, png_const_bytep gamma_table, - png_const_bytep gamma_from_1, png_const_bytep gamma_to_1, - png_const_uint_16pp gamma_16, png_const_uint_16pp gamma_16_from_1, - png_const_uint_16pp gamma_16_to_1, int gamma_shift -#endif - ) +png_do_compose(png_row_infop row_info, png_bytep row, png_structp png_ptr) { - png_bytep sp, dp; +#ifdef PNG_READ_GAMMA_SUPPORTED + png_const_bytep gamma_table = png_ptr->gamma_table; + png_const_bytep gamma_from_1 = png_ptr->gamma_from_1; + png_const_bytep gamma_to_1 = png_ptr->gamma_to_1; + png_const_uint_16pp gamma_16 = png_ptr->gamma_16_table; + png_const_uint_16pp gamma_16_from_1 = png_ptr->gamma_16_from_1; + png_const_uint_16pp gamma_16_to_1 = png_ptr->gamma_16_to_1; + int gamma_shift = png_ptr->gamma_shift; +#endif + + png_bytep sp; png_uint_32 i; png_uint_32 row_width = row_info->width; + int optimize = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0; int shift; - png_debug(1, "in png_do_background"); + png_debug(1, "in png_do_compose"); - if (background != NULL && - (!(row_info->color_type & PNG_COLOR_MASK_ALPHA) || - (row_info->color_type != PNG_COLOR_TYPE_PALETTE && trans_color))) { switch (row_info->color_type) { @@ -2817,10 +3438,10 @@ png_do_background(png_row_infop row_info, png_bytep row, for (i = 0; i < row_width; i++) { if ((png_uint_16)((*sp >> shift) & 0x01) - == trans_color->gray) + == png_ptr->trans_color.gray) { *sp &= (png_byte)((0x7f7f >> (7 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); + *sp |= (png_byte)(png_ptr->background.gray << shift); } if (!shift) @@ -2845,10 +3466,10 @@ png_do_background(png_row_infop row_info, png_bytep row, for (i = 0; i < row_width; i++) { if ((png_uint_16)((*sp >> shift) & 0x03) - == trans_color->gray) + == png_ptr->trans_color.gray) { *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); + *sp |= (png_byte)(png_ptr->background.gray << shift); } else @@ -2879,10 +3500,10 @@ png_do_background(png_row_infop row_info, png_bytep row, for (i = 0; i < row_width; i++) { if ((png_uint_16)((*sp >> shift) & 0x03) - == trans_color->gray) + == png_ptr->trans_color.gray) { *sp &= (png_byte)((0x3f3f >> (6 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); + *sp |= (png_byte)(png_ptr->background.gray << shift); } if (!shift) @@ -2908,10 +3529,10 @@ png_do_background(png_row_infop row_info, png_bytep row, for (i = 0; i < row_width; i++) { if ((png_uint_16)((*sp >> shift) & 0x0f) - == trans_color->gray) + == png_ptr->trans_color.gray) { *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); + *sp |= (png_byte)(png_ptr->background.gray << shift); } else @@ -2942,10 +3563,10 @@ png_do_background(png_row_infop row_info, png_bytep row, for (i = 0; i < row_width; i++) { if ((png_uint_16)((*sp >> shift) & 0x0f) - == trans_color->gray) + == png_ptr->trans_color.gray) { *sp &= (png_byte)((0xf0f >> (4 - shift)) & 0xff); - *sp |= (png_byte)(background->gray << shift); + *sp |= (png_byte)(png_ptr->background.gray << shift); } if (!shift) @@ -2969,8 +3590,8 @@ png_do_background(png_row_infop row_info, png_bytep row, sp = row; for (i = 0; i < row_width; i++, sp++) { - if (*sp == trans_color->gray) - *sp = (png_byte)background->gray; + if (*sp == png_ptr->trans_color.gray) + *sp = (png_byte)png_ptr->background.gray; else *sp = gamma_table[*sp]; @@ -2982,8 +3603,8 @@ png_do_background(png_row_infop row_info, png_bytep row, sp = row; for (i = 0; i < row_width; i++, sp++) { - if (*sp == trans_color->gray) - *sp = (png_byte)background->gray; + if (*sp == png_ptr->trans_color.gray) + *sp = (png_byte)png_ptr->background.gray; } } break; @@ -3001,11 +3622,11 @@ png_do_background(png_row_infop row_info, png_bytep row, v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - if (v == trans_color->gray) + if (v == png_ptr->trans_color.gray) { /* Background is already in screen gamma */ - *sp = (png_byte)((background->gray >> 8) & 0xff); - *(sp + 1) = (png_byte)(background->gray & 0xff); + *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); } else @@ -3026,10 +3647,10 @@ png_do_background(png_row_infop row_info, png_bytep row, v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - if (v == trans_color->gray) + if (v == png_ptr->trans_color.gray) { - *sp = (png_byte)((background->gray >> 8) & 0xff); - *(sp + 1) = (png_byte)(background->gray & 0xff); + *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); } } } @@ -3052,13 +3673,13 @@ png_do_background(png_row_infop row_info, png_bytep row, sp = row; for (i = 0; i < row_width; i++, sp += 3) { - if (*sp == trans_color->red && - *(sp + 1) == trans_color->green && - *(sp + 2) == trans_color->blue) + if (*sp == png_ptr->trans_color.red && + *(sp + 1) == png_ptr->trans_color.green && + *(sp + 2) == png_ptr->trans_color.blue) { - *sp = (png_byte)background->red; - *(sp + 1) = (png_byte)background->green; - *(sp + 2) = (png_byte)background->blue; + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; } else @@ -3075,13 +3696,13 @@ png_do_background(png_row_infop row_info, png_bytep row, sp = row; for (i = 0; i < row_width; i++, sp += 3) { - if (*sp == trans_color->red && - *(sp + 1) == trans_color->green && - *(sp + 2) == trans_color->blue) + if (*sp == png_ptr->trans_color.red && + *(sp + 1) == png_ptr->trans_color.green && + *(sp + 2) == png_ptr->trans_color.blue) { - *sp = (png_byte)background->red; - *(sp + 1) = (png_byte)background->green; - *(sp + 2) = (png_byte)background->blue; + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; } } } @@ -3102,16 +3723,17 @@ png_do_background(png_row_infop row_info, png_bytep row, png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + *(sp + 5)); - if (r == trans_color->red && g == trans_color->green && - b == trans_color->blue) + if (r == png_ptr->trans_color.red && + g == png_ptr->trans_color.green && + b == png_ptr->trans_color.blue) { /* Background is already in screen gamma */ - *sp = (png_byte)((background->red >> 8) & 0xff); - *(sp + 1) = (png_byte)(background->red & 0xff); - *(sp + 2) = (png_byte)((background->green >> 8) & 0xff); - *(sp + 3) = (png_byte)(background->green & 0xff); - *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff); - *(sp + 5) = (png_byte)(background->blue & 0xff); + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } else @@ -3145,15 +3767,16 @@ png_do_background(png_row_infop row_info, png_bytep row, png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + *(sp + 5)); - if (r == trans_color->red && g == trans_color->green && - b == trans_color->blue) + if (r == png_ptr->trans_color.red && + g == png_ptr->trans_color.green && + b == png_ptr->trans_color.blue) { - *sp = (png_byte)((background->red >> 8) & 0xff); - *(sp + 1) = (png_byte)(background->red & 0xff); - *(sp + 2) = (png_byte)((background->green >> 8) & 0xff); - *(sp + 3) = (png_byte)(background->green & 0xff); - *(sp + 4) = (png_byte)((background->blue >> 8) & 0xff); - *(sp + 5) = (png_byte)(background->blue & 0xff); + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } } } @@ -3170,18 +3793,17 @@ png_do_background(png_row_infop row_info, png_bytep row, gamma_table != NULL) { sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 2, dp++) + for (i = 0; i < row_width; i++, sp += 2) { png_uint_16 a = *(sp + 1); if (a == 0xff) - *dp = gamma_table[*sp]; + *sp = gamma_table[*sp]; else if (a == 0) { /* Background is already in screen gamma */ - *dp = (png_byte)background->gray; + *sp = (png_byte)png_ptr->background.gray; } else @@ -3189,8 +3811,10 @@ png_do_background(png_row_infop row_info, png_bytep row, png_byte v, w; v = gamma_to_1[*sp]; - png_composite(w, v, a, background_1->gray); - *dp = gamma_from_1[w]; + png_composite(w, v, a, png_ptr->background_1.gray); + if (!optimize) + w = gamma_from_1[w]; + *sp = w; } } } @@ -3198,24 +3822,15 @@ png_do_background(png_row_infop row_info, png_bytep row, #endif { sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 2, dp++) + for (i = 0; i < row_width; i++, sp += 2) { png_byte a = *(sp + 1); - if (a == 0xff) - *dp = *sp; + if (a == 0) + *sp = (png_byte)png_ptr->background.gray; -#ifdef PNG_READ_GAMMA_SUPPORTED - else if (a == 0) - *dp = (png_byte)background->gray; - - else - png_composite(*dp, *sp, a, background_1->gray); - -#else - *dp = (png_byte)background->gray; -#endif + else if (a < 0xff) + png_composite(*sp, *sp, a, png_ptr->background_1.gray); } } } @@ -3226,8 +3841,7 @@ png_do_background(png_row_infop row_info, png_bytep row, gamma_16_to_1 != NULL) { sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 4, dp += 2) + for (i = 0; i < row_width; i++, sp += 4) { png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) + *(sp + 3)); @@ -3237,69 +3851,56 @@ png_do_background(png_row_infop row_info, png_bytep row, png_uint_16 v; v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *dp = (png_byte)((v >> 8) & 0xff); - *(dp + 1) = (png_byte)(v & 0xff); + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); } -#ifdef PNG_READ_GAMMA_SUPPORTED else if (a == 0) -#else - else -#endif { /* Background is already in screen gamma */ - *dp = (png_byte)((background->gray >> 8) & 0xff); - *(dp + 1) = (png_byte)(background->gray & 0xff); + *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); } -#ifdef PNG_READ_GAMMA_SUPPORTED else { png_uint_16 g, v, w; g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; - png_composite_16(v, g, a, background_1->gray); - w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8]; - *dp = (png_byte)((w >> 8) & 0xff); - *(dp + 1) = (png_byte)(w & 0xff); + png_composite_16(v, g, a, png_ptr->background_1.gray); + if (optimize) + w = v; + else + w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8]; + *sp = (png_byte)((w >> 8) & 0xff); + *(sp + 1) = (png_byte)(w & 0xff); } -#endif } } else #endif { sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 4, dp += 2) + for (i = 0; i < row_width; i++, sp += 4) { png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) + *(sp + 3)); - if (a == (png_uint_16)0xffff) - png_memcpy(dp, sp, 2); - -#ifdef PNG_READ_GAMMA_SUPPORTED - else if (a == 0) -#else - else -#endif + if (a == 0) { - *dp = (png_byte)((background->gray >> 8) & 0xff); - *(dp + 1) = (png_byte)(background->gray & 0xff); + *sp = (png_byte)((png_ptr->background.gray >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); } -#ifdef PNG_READ_GAMMA_SUPPORTED - else + else if (a < 0xffff) { png_uint_16 g, v; g = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - png_composite_16(v, g, a, background_1->gray); - *dp = (png_byte)((v >> 8) & 0xff); - *(dp + 1) = (png_byte)(v & 0xff); + png_composite_16(v, g, a, png_ptr->background_1.gray); + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); } -#endif } } } @@ -3315,24 +3916,23 @@ png_do_background(png_row_infop row_info, png_bytep row, gamma_table != NULL) { sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 4, dp += 3) + for (i = 0; i < row_width; i++, sp += 4) { png_byte a = *(sp + 3); if (a == 0xff) { - *dp = gamma_table[*sp]; - *(dp + 1) = gamma_table[*(sp + 1)]; - *(dp + 2) = gamma_table[*(sp + 2)]; + *sp = gamma_table[*sp]; + *(sp + 1) = gamma_table[*(sp + 1)]; + *(sp + 2) = gamma_table[*(sp + 2)]; } else if (a == 0) { /* Background is already in screen gamma */ - *dp = (png_byte)background->red; - *(dp + 1) = (png_byte)background->green; - *(dp + 2) = (png_byte)background->blue; + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; } else @@ -3340,16 +3940,19 @@ png_do_background(png_row_infop row_info, png_bytep row, png_byte v, w; v = gamma_to_1[*sp]; - png_composite(w, v, a, background_1->red); - *dp = gamma_from_1[w]; + png_composite(w, v, a, png_ptr->background_1.red); + if (!optimize) w = gamma_from_1[w]; + *sp = w; v = gamma_to_1[*(sp + 1)]; - png_composite(w, v, a, background_1->green); - *(dp + 1) = gamma_from_1[w]; + png_composite(w, v, a, png_ptr->background_1.green); + if (!optimize) w = gamma_from_1[w]; + *(sp + 1) = w; v = gamma_to_1[*(sp + 2)]; - png_composite(w, v, a, background_1->blue); - *(dp + 2) = gamma_from_1[w]; + png_composite(w, v, a, png_ptr->background_1.blue); + if (!optimize) w = gamma_from_1[w]; + *(sp + 2) = w; } } } @@ -3357,34 +3960,26 @@ png_do_background(png_row_infop row_info, png_bytep row, #endif { sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 4, dp += 3) + for (i = 0; i < row_width; i++, sp += 4) { png_byte a = *(sp + 3); - if (a == 0xff) + if (a == 0) { - *dp = *sp; - *(dp + 1) = *(sp + 1); - *(dp + 2) = *(sp + 2); + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; } - else if (a == 0) + else if (a < 0xff) { - *dp = (png_byte)background->red; - *(dp + 1) = (png_byte)background->green; - *(dp + 2) = (png_byte)background->blue; - } + png_composite(*sp, *sp, a, png_ptr->background.red); - else - { - png_composite(*dp, *sp, a, background->red); + png_composite(*(sp + 1), *(sp + 1), a, + png_ptr->background.green); - png_composite(*(dp + 1), *(sp + 1), a, - background->green); - - png_composite(*(dp + 2), *(sp + 2), a, - background->blue); + png_composite(*(sp + 2), *(sp + 2), a, + png_ptr->background.blue); } } } @@ -3396,8 +3991,7 @@ png_do_background(png_row_infop row_info, png_bytep row, gamma_16_to_1 != NULL) { sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 8, dp += 6) + for (i = 0; i < row_width; i++, sp += 8) { png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) << 8) + (png_uint_16)(*(sp + 7))); @@ -3407,53 +4001,55 @@ png_do_background(png_row_infop row_info, png_bytep row, png_uint_16 v; v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *dp = (png_byte)((v >> 8) & 0xff); - *(dp + 1) = (png_byte)(v & 0xff); + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; - *(dp + 2) = (png_byte)((v >> 8) & 0xff); - *(dp + 3) = (png_byte)(v & 0xff); + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; - *(dp + 4) = (png_byte)((v >> 8) & 0xff); - *(dp + 5) = (png_byte)(v & 0xff); + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); } else if (a == 0) { /* Background is already in screen gamma */ - *dp = (png_byte)((background->red >> 8) & 0xff); - *(dp + 1) = (png_byte)(background->red & 0xff); - *(dp + 2) = (png_byte)((background->green >> 8) & 0xff); - *(dp + 3) = (png_byte)(background->green & 0xff); - *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff); - *(dp + 5) = (png_byte)(background->blue & 0xff); + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } else { - png_uint_16 v, w, x; + png_uint_16 v, w; v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; - png_composite_16(w, v, a, background_1->red); - - x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; - *dp = (png_byte)((x >> 8) & 0xff); - *(dp + 1) = (png_byte)(x & 0xff); + png_composite_16(w, v, a, png_ptr->background_1.red); + if (!optimize) + w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; + *sp = (png_byte)((w >> 8) & 0xff); + *(sp + 1) = (png_byte)(w & 0xff); v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; - png_composite_16(w, v, a, background_1->green); + png_composite_16(w, v, a, png_ptr->background_1.green); + if (!optimize) + w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; - x = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; - *(dp + 2) = (png_byte)((x >> 8) & 0xff); - *(dp + 3) = (png_byte)(x & 0xff); + *(sp + 2) = (png_byte)((w >> 8) & 0xff); + *(sp + 3) = (png_byte)(w & 0xff); v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; - png_composite_16(w, v, a, background_1->blue); + png_composite_16(w, v, a, png_ptr->background_1.blue); + if (!optimize) + w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> 8]; - x = gamma_16_from_1[(w & 0xff) >> gamma_shift][w >> 8]; - *(dp + 4) = (png_byte)((x >> 8) & 0xff); - *(dp + 5) = (png_byte)(x & 0xff); + *(sp + 4) = (png_byte)((w >> 8) & 0xff); + *(sp + 5) = (png_byte)(w & 0xff); } } } @@ -3462,28 +4058,22 @@ png_do_background(png_row_infop row_info, png_bytep row, #endif { sp = row; - dp = row; - for (i = 0; i < row_width; i++, sp += 8, dp += 6) + for (i = 0; i < row_width; i++, sp += 8) { png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) << 8) + (png_uint_16)(*(sp + 7))); - if (a == (png_uint_16)0xffff) + if (a == 0) { - png_memcpy(dp, sp, 6); + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } - else if (a == 0) - { - *dp = (png_byte)((background->red >> 8) & 0xff); - *(dp + 1) = (png_byte)(background->red & 0xff); - *(dp + 2) = (png_byte)((background->green >> 8) & 0xff); - *(dp + 3) = (png_byte)(background->green & 0xff); - *(dp + 4) = (png_byte)((background->blue >> 8) & 0xff); - *(dp + 5) = (png_byte)(background->blue & 0xff); - } - - else + else if (a < 0xffff) { png_uint_16 v; @@ -3493,17 +4083,17 @@ png_do_background(png_row_infop row_info, png_bytep row, png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + *(sp + 5)); - png_composite_16(v, r, a, background->red); - *dp = (png_byte)((v >> 8) & 0xff); - *(dp + 1) = (png_byte)(v & 0xff); + png_composite_16(v, r, a, png_ptr->background.red); + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); - png_composite_16(v, g, a, background->green); - *(dp + 2) = (png_byte)((v >> 8) & 0xff); - *(dp + 3) = (png_byte)(v & 0xff); + png_composite_16(v, g, a, png_ptr->background.green); + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); - png_composite_16(v, b, a, background->blue); - *(dp + 4) = (png_byte)((v >> 8) & 0xff); - *(dp + 5) = (png_byte)(v & 0xff); + png_composite_16(v, b, a, png_ptr->background.blue); + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); } } } @@ -3514,16 +4104,6 @@ png_do_background(png_row_infop row_info, png_bytep row, default: break; } - - if (row_info->color_type & PNG_COLOR_MASK_ALPHA) - { - row_info->color_type = (png_byte)(row_info->color_type & - ~PNG_COLOR_MASK_ALPHA); - row_info->channels--; - row_info->pixel_depth = (png_byte)(row_info->channels * - row_info->bit_depth); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } } } #endif @@ -3536,10 +4116,12 @@ png_do_background(png_row_infop row_info, png_bytep row, * build_gamma_table(). */ void /* PRIVATE */ -png_do_gamma(png_row_infop row_info, png_bytep row, - png_const_bytep gamma_table, png_const_uint_16pp gamma_16_table, - int gamma_shift) +png_do_gamma(png_row_infop row_info, png_bytep row, png_structp png_ptr) { + png_const_bytep gamma_table = png_ptr->gamma_table; + png_const_uint_16pp gamma_16_table = png_ptr->gamma_16_table; + int gamma_shift = png_ptr->gamma_shift; + png_bytep sp; png_uint_32 i; png_uint_32 row_width=row_info->width; @@ -3729,6 +4311,73 @@ png_do_gamma(png_row_infop row_info, png_bytep row, } #endif +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +/* Encode the alpha channel to the output gamma (the input channel is always + * linear.) Called only with color types that have an alpha channel. Needs the + * from_1 tables. + */ +void /* PRIVATE */ +png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structp png_ptr) +{ + png_uint_32 row_width = row_info->width; + + png_debug(1, "in png_do_encode_alpha"); + + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) + { + if (row_info->bit_depth == 8) + { + PNG_CONST png_bytep table = png_ptr->gamma_from_1; + + if (table != NULL) + { + PNG_CONST int step = + (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 4 : 2; + + /* The alpha channel is the last component: */ + row += step - 1; + + for (; row_width > 0; --row_width, row += step) + *row = table[*row]; + + return; + } + } + + else if (row_info->bit_depth == 16) + { + PNG_CONST png_uint_16pp table = png_ptr->gamma_16_from_1; + PNG_CONST int gamma_shift = png_ptr->gamma_shift; + + if (table != NULL) + { + PNG_CONST int step = + (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 8 : 4; + + /* The alpha channel is the last component: */ + row += step - 2; + + for (; row_width > 0; --row_width, row += step) + { + png_uint_16 v; + + v = table[*(row + 1) >> gamma_shift][*row]; + *row = (png_byte)((v >> 8) & 0xff); + *(row + 1) = (png_byte)(v & 0xff); + } + + return; + } + } + } + + /* Only get to here if called with a weird row_info; no harm has been done, + * so just issue a warning. + */ + png_warning(png_ptr, "png_do_encode_alpha: unexpected call"); +} +#endif + #ifdef PNG_READ_EXPAND_SUPPORTED /* Expands a palette row to an RGB or RGBA row depending * upon whether you supply trans and num_trans. @@ -3834,7 +4483,7 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row, if (row_info->bit_depth == 8) { { - if (trans_alpha != NULL) + if (num_trans > 0) { sp = row + (png_size_t)row_width - 1; dp = row + (png_size_t)(row_width << 2) - 1; @@ -3888,7 +4537,7 @@ png_do_expand_palette(png_row_infop row_info, png_bytep row, */ void /* PRIVATE */ png_do_expand(png_row_infop row_info, png_bytep row, - png_const_color_16p trans_value) + png_const_color_16p trans_color) { int shift, value; png_bytep sp, dp; @@ -3900,7 +4549,7 @@ png_do_expand(png_row_infop row_info, png_bytep row, { if (row_info->color_type == PNG_COLOR_TYPE_GRAY) { - png_uint_16 gray = (png_uint_16)(trans_value ? trans_value->gray : 0); + png_uint_16 gray = (png_uint_16)(trans_color ? trans_color->gray : 0); if (row_info->bit_depth < 8) { @@ -3992,7 +4641,7 @@ png_do_expand(png_row_infop row_info, png_bytep row, row_info->rowbytes = row_width; } - if (trans_value != NULL) + if (trans_color != NULL) { if (row_info->bit_depth == 8) { @@ -4044,13 +4693,13 @@ png_do_expand(png_row_infop row_info, png_bytep row, row_width); } } - else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_value) + else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_color) { if (row_info->bit_depth == 8) { - png_byte red = (png_byte)(trans_value->red & 0xff); - png_byte green = (png_byte)(trans_value->green & 0xff); - png_byte blue = (png_byte)(trans_value->blue & 0xff); + png_byte red = (png_byte)(trans_color->red & 0xff); + png_byte green = (png_byte)(trans_color->green & 0xff); + png_byte blue = (png_byte)(trans_color->blue & 0xff); sp = row + (png_size_t)row_info->rowbytes - 1; dp = row + (png_size_t)(row_width << 2) - 1; for (i = 0; i < row_width; i++) @@ -4068,12 +4717,12 @@ png_do_expand(png_row_infop row_info, png_bytep row, } else if (row_info->bit_depth == 16) { - png_byte red_high = (png_byte)((trans_value->red >> 8) & 0xff); - png_byte green_high = (png_byte)((trans_value->green >> 8) & 0xff); - png_byte blue_high = (png_byte)((trans_value->blue >> 8) & 0xff); - png_byte red_low = (png_byte)(trans_value->red & 0xff); - png_byte green_low = (png_byte)(trans_value->green & 0xff); - png_byte blue_low = (png_byte)(trans_value->blue & 0xff); + png_byte red_high = (png_byte)((trans_color->red >> 8) & 0xff); + png_byte green_high = (png_byte)((trans_color->green >> 8) & 0xff); + png_byte blue_high = (png_byte)((trans_color->blue >> 8) & 0xff); + png_byte red_low = (png_byte)(trans_color->red & 0xff); + png_byte green_low = (png_byte)(trans_color->green & 0xff); + png_byte blue_low = (png_byte)(trans_color->blue & 0xff); sp = row + row_info->rowbytes - 1; dp = row + (png_size_t)(row_width << 3) - 1; for (i = 0; i < row_width; i++) @@ -4236,6 +4885,7 @@ png_do_quantize(png_row_infop row_info, png_bytep row, } } #endif /* PNG_READ_QUANTIZE_SUPPORTED */ +#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ #ifdef PNG_MNG_FEATURES_SUPPORTED /* Undoes intrapixel differencing */ diff --git a/src/libpng/pngrutil.c b/src/libpng/pngrutil.c index 1f510f3a7..34031b21d 100644 --- a/src/libpng/pngrutil.c +++ b/src/libpng/pngrutil.c @@ -1,7 +1,7 @@ /* pngrutil.c - utilities to read a PNG file * - * Last changed in libpng 1.5.2 [March 31, 2011] + * Last changed in libpng 1.5.4 [July 7, 2011] * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -278,8 +278,7 @@ png_crc_error(png_structp png_ptr) return (0); } -#if defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) || \ - defined(PNG_READ_iCCP_SUPPORTED) +#ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED static png_size_t png_inflate(png_structp png_ptr, png_bytep data, png_size_t size, png_bytep output, png_size_t output_size) @@ -370,41 +369,31 @@ png_inflate(png_structp png_ptr, png_bytep data, png_size_t size, * and the error message is dumped into the uncompressed * buffer if available. */ +# ifdef PNG_WARNINGS_SUPPORTED { - PNG_CONST char *msg; -#ifdef PNG_CONSOLE_IO_SUPPORTED - char umsg[52]; -#endif + png_const_charp msg; + if (png_ptr->zstream.msg != 0) msg = png_ptr->zstream.msg; - else + else switch (ret) { -#ifdef PNG_CONSOLE_IO_SUPPORTED - switch (ret) - { - case Z_BUF_ERROR: - msg = "Buffer error in compressed datastream in %s chunk"; - break; + case Z_BUF_ERROR: + msg = "Buffer error in compressed datastream"; + break; - case Z_DATA_ERROR: - msg = "Data error in compressed datastream in %s chunk"; - break; + case Z_DATA_ERROR: + msg = "Data error in compressed datastream"; + break; - default: - msg = "Incomplete compressed datastream in %s chunk"; - break; - } - - png_snprintf(umsg, sizeof umsg, msg, png_ptr->chunk_name); - msg = umsg; -#else - msg = "Damaged compressed datastream in chunk other than IDAT"; -#endif + default: + msg = "Incomplete compressed datastream"; + break; } - png_warning(png_ptr, msg); + png_chunk_warning(png_ptr, msg); } +# endif /* 0 means an error - notice that this code simply ignores * zero length compressed chunks as a result. @@ -438,8 +427,8 @@ png_decompress_chunk(png_structp png_ptr, int comp_type, png_size_t expanded_size = png_inflate(png_ptr, (png_bytep)(png_ptr->chunkdata + prefix_size), chunklength - prefix_size, - 0, /*output*/ - 0); /*output size*/ + 0, /* output */ + 0); /* output size */ /* Now check the limits on this chunk - if the limit fails the * compressed data will be removed, the prefix will remain. @@ -500,15 +489,9 @@ png_decompress_chunk(png_structp png_ptr, int comp_type, else /* if (comp_type != PNG_COMPRESSION_TYPE_BASE) */ { -#ifdef PNG_STDIO_SUPPORTED - char umsg[50]; - - png_snprintf(umsg, sizeof umsg, - "Unknown zTXt compression type %d", comp_type); - png_warning(png_ptr, umsg); -#else - png_warning(png_ptr, "Unknown zTXt compression type"); -#endif + PNG_WARNING_PARAMETERS(p) + png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_d, comp_type); + png_formatted_warning(png_ptr, p, "Unknown zTXt compression type @1"); /* The recovery is to simply drop the data. */ } @@ -536,7 +519,7 @@ png_decompress_chunk(png_structp png_ptr, int comp_type, *newlength = prefix_size; } -#endif +#endif /* PNG_READ_COMPRESSED_TEXT_SUPPORTED */ /* Read and check the IDHR chunk */ void /* PRIVATE */ @@ -846,12 +829,10 @@ png_handle_gAMA(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { if (PNG_OUT_OF_RANGE(igamma, 45500L, 500)) { - png_warning(png_ptr, - "Ignoring incorrect gAMA value when sRGB is also present"); - -# ifdef PNG_CONSOLE_IO_SUPPORTED - fprintf(stderr, "gamma = (%d/100000)", (int)igamma); -# endif + PNG_WARNING_PARAMETERS(p) + png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, igamma); + png_formatted_warning(png_ptr, p, + "Ignoring incorrect gAMA value @1 when sRGB is also present"); return; } } @@ -1020,21 +1001,52 @@ png_handle_cHRM(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) PNG_OUT_OF_RANGE(x_blue, 15000, 1000) || PNG_OUT_OF_RANGE(y_blue, 6000, 1000)) { - png_warning(png_ptr, - "Ignoring incorrect cHRM value when sRGB is also present"); + PNG_WARNING_PARAMETERS(p) -#ifdef PNG_CONSOLE_IO_SUPPORTED - fprintf(stderr, "wx=%d, wy=%d, rx=%d, ry=%d\n", - x_white, y_white, x_red, y_red); + png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, x_white); + png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_fixed, y_white); + png_warning_parameter_signed(p, 3, PNG_NUMBER_FORMAT_fixed, x_red); + png_warning_parameter_signed(p, 4, PNG_NUMBER_FORMAT_fixed, y_red); + png_warning_parameter_signed(p, 5, PNG_NUMBER_FORMAT_fixed, x_green); + png_warning_parameter_signed(p, 6, PNG_NUMBER_FORMAT_fixed, y_green); + png_warning_parameter_signed(p, 7, PNG_NUMBER_FORMAT_fixed, x_blue); + png_warning_parameter_signed(p, 8, PNG_NUMBER_FORMAT_fixed, y_blue); - fprintf(stderr, "gx=%d, gy=%d, bx=%d, by=%d\n", - x_green, y_green, x_blue, y_blue); -#endif /* PNG_CONSOLE_IO_SUPPORTED */ + png_formatted_warning(png_ptr, p, + "Ignoring incorrect cHRM white(@1,@2) r(@3,@4)g(@5,@6)b(@7,@8) " + "when sRGB is also present"); } return; } #endif /* PNG_READ_sRGB_SUPPORTED */ +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* Store the _white values as default coefficients for the rgb to gray + * operation if it is supported. + */ + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == 0) + { + /* png_set_background has not been called, the coefficients must be in + * range for the following to work without overflow. + */ + if (y_red <= (1<<17) && y_green <= (1<<17) && y_blue <= (1<<17)) + { + /* The y values are chromaticities: Y/X+Y+Z, the weights for the gray + * transformation are simply the normalized Y values for red, green and + * blue scaled by 32768. + */ + png_uint_32 w = y_red + y_green + y_blue; + + png_ptr->rgb_to_gray_red_coeff = (png_uint_16)(((png_uint_32)y_red * + 32768)/w); + png_ptr->rgb_to_gray_green_coeff = (png_uint_16)(((png_uint_32)y_green + * 32768)/w); + png_ptr->rgb_to_gray_blue_coeff = (png_uint_16)(((png_uint_32)y_blue * + 32768)/w); + } + } +#endif + png_set_cHRM_fixed(png_ptr, info_ptr, x_white, y_white, x_red, y_red, x_green, y_green, x_blue, y_blue); } @@ -1096,11 +1108,13 @@ png_handle_sRGB(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { if (PNG_OUT_OF_RANGE(info_ptr->gamma, 45500L, 500)) { - png_warning(png_ptr, - "Ignoring incorrect gAMA value when sRGB is also present"); -#ifdef PNG_CONSOLE_IO_SUPPORTED - fprintf(stderr, "incorrect gamma=(%d/100000)\n", info_ptr->gamma); -#endif + PNG_WARNING_PARAMETERS(p) + + png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_fixed, + info_ptr->gamma); + + png_formatted_warning(png_ptr, p, + "Ignoring incorrect gAMA value @1 when sRGB is also present"); } } #endif /* PNG_READ_gAMA_SUPPORTED */ @@ -1240,23 +1254,15 @@ png_handle_iCCP(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) /* And the following guarantees that profile_size == profile_length. */ if (profile_size > profile_length) { + PNG_WARNING_PARAMETERS(p) + png_free(png_ptr, png_ptr->chunkdata); png_ptr->chunkdata = NULL; -#ifdef PNG_STDIO_SUPPORTED - { - char umsg[80]; - png_snprintf2(umsg, 80, - "Ignoring iCCP chunk with declared size = %u " - "and actual length = %u", - (unsigned int) profile_size, - (unsigned int) profile_length); - png_warning(png_ptr, umsg); - } -#else - png_warning(png_ptr, - "Ignoring iCCP chunk with uncompressed size mismatch"); -#endif + png_warning_parameter_unsigned(p, 1, PNG_NUMBER_FORMAT_u, profile_size); + png_warning_parameter_unsigned(p, 2, PNG_NUMBER_FORMAT_u, profile_length); + png_formatted_warning(png_ptr, p, + "Ignoring iCCP chunk with declared size = @1 and actual length = @2"); return; } @@ -1565,6 +1571,7 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) { png_size_t truelen; png_byte buf[6]; + png_color_16 background; png_debug(1, "in png_handle_bKGD"); @@ -1621,7 +1628,7 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) */ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - png_ptr->background.index = buf[0]; + background.index = buf[0]; if (info_ptr && info_ptr->num_palette) { @@ -1631,33 +1638,36 @@ png_handle_bKGD(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) return; } - png_ptr->background.red = - (png_uint_16)png_ptr->palette[buf[0]].red; - - png_ptr->background.green = - (png_uint_16)png_ptr->palette[buf[0]].green; - - png_ptr->background.blue = - (png_uint_16)png_ptr->palette[buf[0]].blue; + background.red = (png_uint_16)png_ptr->palette[buf[0]].red; + background.green = (png_uint_16)png_ptr->palette[buf[0]].green; + background.blue = (png_uint_16)png_ptr->palette[buf[0]].blue; } + + else + background.red = background.green = background.blue = 0; + + background.gray = 0; } else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */ { - png_ptr->background.red = - png_ptr->background.green = - png_ptr->background.blue = - png_ptr->background.gray = png_get_uint_16(buf); + background.index = 0; + background.red = + background.green = + background.blue = + background.gray = png_get_uint_16(buf); } else { - png_ptr->background.red = png_get_uint_16(buf); - png_ptr->background.green = png_get_uint_16(buf + 2); - png_ptr->background.blue = png_get_uint_16(buf + 4); + background.index = 0; + background.red = png_get_uint_16(buf); + background.green = png_get_uint_16(buf + 2); + background.blue = png_get_uint_16(buf + 4); + background.gray = 0; } - png_set_bKGD(png_ptr, info_ptr, &(png_ptr->background)); + png_set_bKGD(png_ptr, info_ptr, &background); } #endif @@ -1982,6 +1992,14 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) return; } + /* Need unit type, width, \0, height: minimum 4 bytes */ + else if (length < 4) + { + png_warning(png_ptr, "sCAL chunk too short"); + png_crc_finish(png_ptr, length); + return; + } + png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)", length + 1); @@ -2017,23 +2035,29 @@ png_handle_sCAL(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) /* Validate the ASCII numbers, need two ASCII numbers separated by * a '\0' and they need to fit exactly in the chunk data. */ - i = 0; + 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; - if (png_ptr->chunkdata[i] == 45 /* negative height */ || - !png_check_fp_number(png_ptr->chunkdata, slength, &state, &i) || + state = 0; + 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], @@ -2660,6 +2684,14 @@ png_combine_row(png_structp png_ptr, png_bytep row, int mask) { png_debug(1, "in png_combine_row"); + /* Added in 1.5.4: the row_info should match the information returned by any + * call to png_read_update_info at this point. Do not continue if we got + * this wrong. + */ + if (png_ptr->info_rowbytes != 0 && png_ptr->info_rowbytes != + PNG_ROWBYTES(png_ptr->row_info.pixel_depth, png_ptr->width)) + png_error(png_ptr, "internal row size calculation error"); + if (mask == 0xff) { png_memcpy(row, png_ptr->row_buf + 1, @@ -3398,7 +3430,9 @@ png_read_start_row(png_structp png_ptr) png_debug(1, "in png_read_start_row"); png_ptr->zstream.avail_in = 0; +#ifdef PNG_READ_TRANSFORMS_SUPPORTED png_init_read_transformations(png_ptr); +#endif #ifdef PNG_READ_INTERLACING_SUPPORTED if (png_ptr->interlaced) { diff --git a/src/libpng/pngset.c b/src/libpng/pngset.c index 2cfcf33bd..7eaad7dd4 100644 --- a/src/libpng/pngset.c +++ b/src/libpng/pngset.c @@ -1,7 +1,7 @@ /* pngset.c - storage of image information into info struct * - * Last changed in libpng 1.5.1 [February 3, 2011] + * Last changed in libpng 1.5.4 [July 7, 2011] * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -94,15 +94,16 @@ png_set_gAMA_fixed(png_structp png_ptr, png_infop info_ptr, png_fixed_point if (png_ptr == NULL || info_ptr == NULL) return; - /* Previously these values were limited, however they must be - * wrong, therefore storing them (and setting PNG_INFO_gAMA) - * must be wrong too. + /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't + * occur. Since the fixed point representation is assymetrical it is + * possible for 1/gamma to overflow the limit of 21474 and this means the + * gamma value must be at least 5/100000 and hence at most 20000.0. For + * safety the limits here are a little narrower. The values are 0.00016 to + * 6250.0, which are truely ridiculous gammma values (and will produce + * displays that are all black or all white.) */ - if (file_gamma > (png_fixed_point)PNG_UINT_31_MAX) - png_warning(png_ptr, "Gamma too large, ignored"); - - else if (file_gamma <= 0) - png_warning(png_ptr, "Negative or zero gamma ignored"); + if (file_gamma < 16 || file_gamma > 625000000) + png_warning(png_ptr, "Out of range gamma value ignored"); else { @@ -340,12 +341,12 @@ png_set_sCAL_s(png_structp png_ptr, png_infop info_ptr, if (unit != 1 && unit != 2) png_error(png_ptr, "Invalid sCAL unit"); - if (swidth == NULL || (lengthw = png_strlen(swidth)) <= 0 || - swidth[0] == 45 /*'-'*/ || !png_check_fp_string(swidth, lengthw)) + if (swidth == NULL || (lengthw = png_strlen(swidth)) == 0 || + swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw)) png_error(png_ptr, "Invalid sCAL width"); - if (sheight == NULL || (lengthh = png_strlen(sheight)) <= 0 || - sheight[0] == 45 /*'-'*/ || !png_check_fp_string(sheight, lengthh)) + if (sheight == NULL || (lengthh = png_strlen(sheight)) == 0 || + sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh)) png_error(png_ptr, "Invalid sCAL height"); info_ptr->scal_unit = (png_byte)unit; @@ -545,7 +546,7 @@ png_set_sRGB_gAMA_and_cHRM(png_structp png_ptr, png_infop info_ptr, png_set_sRGB(png_ptr, info_ptr, srgb_intent); # ifdef PNG_gAMA_SUPPORTED - png_set_gAMA_fixed(png_ptr, info_ptr, 45455L); + png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE); # endif # ifdef PNG_cHRM_SUPPORTED diff --git a/src/libpng/pngstruct.h b/src/libpng/pngstruct.h index 8d781faef..93b2b3eb0 100644 --- a/src/libpng/pngstruct.h +++ b/src/libpng/pngstruct.h @@ -5,7 +5,7 @@ * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * - * Last changed in libpng 1.5.0 [January 6, 2011] + * Last changed in libpng 1.5.4 [July 7, 2011] * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -29,11 +29,13 @@ struct png_struct_def { #ifdef PNG_SETJMP_SUPPORTED - jmp_buf png_jmpbuf; /* used in png_error */ + jmp_buf longjmp_buffer; /* used in png_error */ png_longjmp_ptr longjmp_fn;/* setjmp non-local goto function. */ #endif png_error_ptr error_fn; /* function for printing errors and aborting */ +#ifdef PNG_WARNINGS_SUPPORTED png_error_ptr warning_fn; /* function for printing warnings */ +#endif png_voidp error_ptr; /* user supplied struct for error functions */ png_rw_ptr write_data_fn; /* function for writing output data */ png_rw_ptr read_data_fn; /* function for reading input data */ @@ -64,11 +66,36 @@ struct png_struct_def z_stream zstream; /* pointer to decompression structure (below) */ png_bytep zbuf; /* buffer for zlib */ uInt zbuf_size; /* size of zbuf (typically 65536) */ +#ifdef PNG_WRITE_SUPPORTED + +/* Added in 1.5.4: state to keep track of whether the zstream has been + * initialized and if so whether it is for IDAT or some other chunk. + */ +#define PNG_ZLIB_UNINITIALIZED 0 +#define PNG_ZLIB_FOR_IDAT 1 +#define PNG_ZLIB_FOR_TEXT 2 /* anything other than IDAT */ +#define PNG_ZLIB_USE_MASK 3 /* bottom two bits */ +#define PNG_ZLIB_IN_USE 4 /* a flag value */ + + png_uint_32 zlib_state; /* State of zlib initialization */ +/* End of material added at libpng 1.5.4 */ + int zlib_level; /* holds zlib compression level */ int zlib_method; /* holds zlib compression method */ int zlib_window_bits; /* holds zlib compression window bits */ int zlib_mem_level; /* holds zlib compression memory level */ int zlib_strategy; /* holds zlib compression strategy */ +#endif +/* Added at libpng 1.5.4 */ +#if defined(PNG_WRITE_COMPRESSED_TEXT_SUPPORTED) || \ + defined(PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED) + int zlib_text_level; /* holds zlib compression level */ + int zlib_text_method; /* holds zlib compression method */ + int zlib_text_window_bits; /* holds zlib compression window bits */ + int zlib_text_mem_level; /* holds zlib compression memory level */ + int zlib_text_strategy; /* holds zlib compression strategy */ +#endif +/* End of material added at libpng 1.5.4 */ png_uint_32 width; /* width of image in pixels */ png_uint_32 height; /* height of image in pixels */ @@ -84,6 +111,7 @@ struct png_struct_def png_bytep avg_row; /* buffer to save "avg" row when filtering */ png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */ png_row_info row_info; /* used for transformation routines */ + png_size_t info_rowbytes; /* Added in 1.5.4: cache of updated row bytes */ png_uint_32 idat_size; /* current IDAT size for read */ png_uint_32 crc; /* current chunk CRC value */ @@ -108,7 +136,8 @@ struct png_struct_def png_uint_16 filler; /* filler bytes for pixel expansion */ #endif -#ifdef PNG_bKGD_SUPPORTED +#if defined(PNG_bKGD_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) png_byte background_gamma_type; png_fixed_point background_gamma; png_color_16 background; /* background color in screen gamma space */ @@ -209,7 +238,7 @@ struct png_struct_def #endif #ifdef PNG_TIME_RFC1123_SUPPORTED - png_charp time_buffer; /* String to hold RFC 1123 time text */ + char time_buffer[29]; /* String to hold RFC 1123 time text */ #endif /* New members added in libpng-1.0.6 */ diff --git a/src/libpng/pngtrans.c b/src/libpng/pngtrans.c index cf7622cdc..6a6908dcd 100644 --- a/src/libpng/pngtrans.c +++ b/src/libpng/pngtrans.c @@ -1,7 +1,7 @@ /* pngtrans.c - transforms the data in a row (used by both readers and writers) * - * Last changed in libpng 1.5.2 [March 31, 2011] + * Last changed in libpng 1.5.4 [July 7, 2011] * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -442,7 +442,11 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) /* At the start sp will point to the first byte to copy and dp to where * it is copied to. ep always points just beyond the end of the row, so * the loop simply copies (channels-1) channels until sp reaches ep. + * + * at_start: 0 -- convert AG, XG, ARGB, XRGB, AAGG, XXGG, etc. + * nonzero -- convert GA, GX, RGBA, RGBX, GGAA, RRGGBBXX, etc. */ + /* GA, GX, XG cases */ if (row_info->channels == 2) { @@ -450,7 +454,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) { if (at_start) /* Skip initial filler */ ++sp; - else /* Skip initial channels and, for sp, the filler */ + else /* Skip initial channel and, for sp, the filler */ sp += 2, ++dp; /* For a 1 pixel wide image there is nothing to do */ @@ -462,9 +466,9 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) else if (row_info->bit_depth == 16) { - if (at_start) + if (at_start) /* Skip initial filler */ sp += 2; - else + else /* Skip initial channel and, for sp, the filler */ sp += 4, dp += 2; while (sp < ep) @@ -502,9 +506,9 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) else if (row_info->bit_depth == 16) { - if (at_start) + if (at_start) /* Skip initial filler */ sp += 2; - else + else /* Skip initial channels and, for sp, the filler */ sp += 8, dp += 6; while (sp < ep) diff --git a/src/libpng/pngwrite.c b/src/libpng/pngwrite.c index 9277a9516..d1af9e899 100644 --- a/src/libpng/pngwrite.c +++ b/src/libpng/pngwrite.c @@ -1,7 +1,7 @@ /* pngwrite.c - general routines to write a PNG file * - * Last changed in libpng 1.5.1 [February 3, 2011] + * Last changed in libpng 1.5.4 [July 7, 2011] * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -99,8 +99,10 @@ png_write_info_before_PLTE(png_structp png_ptr, png_infop info_ptr) int keep = png_handle_as_unknown(png_ptr, up->name); if (keep != PNG_HANDLE_CHUNK_NEVER && - up->location && !(up->location & PNG_HAVE_PLTE) && + up->location && + !(up->location & PNG_HAVE_PLTE) && !(up->location & PNG_HAVE_IDAT) && + !(up->location & PNG_AFTER_IDAT) && ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) { @@ -273,8 +275,10 @@ png_write_info(png_structp png_ptr, png_infop info_ptr) { int keep = png_handle_as_unknown(png_ptr, up->name); if (keep != PNG_HANDLE_CHUNK_NEVER && - up->location && (up->location & PNG_HAVE_PLTE) && + up->location && + (up->location & PNG_HAVE_PLTE) && !(up->location & PNG_HAVE_IDAT) && + !(up->location & PNG_AFTER_IDAT) && ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) { @@ -380,7 +384,8 @@ png_write_end(png_structp png_ptr, png_infop info_ptr) { int keep = png_handle_as_unknown(png_ptr, up->name); if (keep != PNG_HANDLE_CHUNK_NEVER && - up->location && (up->location & PNG_AFTER_IDAT) && + up->location && + (up->location & PNG_AFTER_IDAT) && ((up->name[3] & 0x20) || keep == PNG_HANDLE_CHUNK_ALWAYS || (png_ptr->flags & PNG_FLAG_KEEP_UNSAFE_CHUNKS))) { @@ -462,10 +467,9 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, png_structp png_ptr; #ifdef PNG_SETJMP_SUPPORTED #ifdef USE_FAR_KEYWORD - jmp_buf png_jmpbuf; + jmp_buf tmp_jmpbuf; #endif #endif - int i; png_debug(1, "in png_create_write_struct"); @@ -489,12 +493,12 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, encounter a png_error() will longjmp here. Since the jmpbuf is then meaningless we abort instead of returning. */ #ifdef USE_FAR_KEYWORD - if (setjmp(png_jmpbuf)) + if (setjmp(tmp_jmpbuf)) #else if (setjmp(png_jmpbuf(png_ptr))) /* sets longjmp to match setjmp */ #endif #ifdef USE_FAR_KEYWORD - png_memcpy(png_jmpbuf(png_ptr), png_jmpbuf, png_sizeof(jmp_buf)); + png_memcpy(png_jmpbuf(png_ptr), tmp_jmpbuf, png_sizeof(jmp_buf)); #endif PNG_ABORT(); #endif @@ -504,49 +508,8 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, #endif /* PNG_USER_MEM_SUPPORTED */ png_set_error_fn(png_ptr, error_ptr, error_fn, warn_fn); - if (user_png_ver) - { - i = 0; - do - { - if (user_png_ver[i] != png_libpng_ver[i]) - png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; - } while (png_libpng_ver[i++]); - } - - if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) - { - /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so - * we must recompile any applications that use any older library version. - * For versions after libpng 1.0, we will be compatible, so we need - * only check the first digit. - */ - if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || - (user_png_ver[0] == '1' && user_png_ver[2] != png_libpng_ver[2]) || - (user_png_ver[0] == '0' && user_png_ver[2] < '9')) - { -#ifdef PNG_CONSOLE_IO_SUPPORTED - char msg[80]; - - if (user_png_ver) - { - png_snprintf2(msg, 80, - "Application built with libpng-%.20s" - " but running with %.20s", - user_png_ver, - png_libpng_ver); - png_warning(png_ptr, msg); - } -#else - png_warning(png_ptr, - "Incompatible libpng version in application and library"); -#endif -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - png_ptr->flags = 0; -#endif - png_cleanup_needed = 1; - } - } + if (!png_user_version_check(png_ptr, user_png_ver)) + png_cleanup_needed = 1; /* Initialize zbuf - compression buffer */ png_ptr->zbuf_size = PNG_ZBUF_SIZE; @@ -805,9 +768,11 @@ png_write_row(png_structp png_ptr, png_const_bytep row) } #endif +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED /* Handle other transformations */ if (png_ptr->transformations) png_do_write_transformations(png_ptr); +#endif #ifdef PNG_MNG_FEATURES_SUPPORTED /* Write filter_method 64 (intrapixel differencing) only if @@ -884,8 +849,6 @@ png_write_flush(png_structp png_ptr) { /* Write the IDAT and reset the zlib output buffer */ png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; wrote_IDAT = 1; } } while (wrote_IDAT == 1); @@ -896,8 +859,6 @@ png_write_flush(png_structp png_ptr) /* Write the IDAT and reset the zlib output buffer */ png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size - png_ptr->zstream.avail_out); - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; } png_ptr->flush_rows = 0; png_flush(png_ptr); @@ -983,7 +944,9 @@ png_write_destroy(png_structp png_ptr) jmp_buf tmp_jmp; /* Save jump buffer */ #endif png_error_ptr error_fn; +#ifdef PNG_WARNINGS_SUPPORTED png_error_ptr warning_fn; +#endif png_voidp error_ptr; #ifdef PNG_USER_MEM_SUPPORTED png_free_ptr free_fn; @@ -992,7 +955,8 @@ png_write_destroy(png_structp png_ptr) png_debug(1, "in png_write_destroy"); /* Free any memory zlib uses */ - deflateEnd(&png_ptr->zstream); + if (png_ptr->zlib_state != PNG_ZLIB_UNINITIALIZED) + deflateEnd(&png_ptr->zstream); /* Free our memory. png_free checks NULL for us. */ png_free(png_ptr, png_ptr->zbuf); @@ -1005,10 +969,6 @@ png_write_destroy(png_structp png_ptr) png_free(png_ptr, png_ptr->paeth_row); #endif -#ifdef PNG_TIME_RFC1123_SUPPORTED - png_free(png_ptr, png_ptr->time_buffer); -#endif - #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* Use this to save a little code space, it doesn't free the filter_costs */ png_reset_filter_heuristics(png_ptr); @@ -1018,11 +978,13 @@ png_write_destroy(png_structp png_ptr) #ifdef PNG_SETJMP_SUPPORTED /* Reset structure */ - png_memcpy(tmp_jmp, png_ptr->png_jmpbuf, png_sizeof(jmp_buf)); + png_memcpy(tmp_jmp, png_ptr->longjmp_buffer, png_sizeof(jmp_buf)); #endif error_fn = png_ptr->error_fn; +#ifdef PNG_WARNINGS_SUPPORTED warning_fn = png_ptr->warning_fn; +#endif error_ptr = png_ptr->error_ptr; #ifdef PNG_USER_MEM_SUPPORTED free_fn = png_ptr->free_fn; @@ -1031,14 +993,16 @@ png_write_destroy(png_structp png_ptr) png_memset(png_ptr, 0, png_sizeof(png_struct)); png_ptr->error_fn = error_fn; +#ifdef PNG_WARNINGS_SUPPORTED png_ptr->warning_fn = warning_fn; +#endif png_ptr->error_ptr = error_ptr; #ifdef PNG_USER_MEM_SUPPORTED png_ptr->free_fn = free_fn; #endif #ifdef PNG_SETJMP_SUPPORTED - png_memcpy(png_ptr->png_jmpbuf, tmp_jmp, png_sizeof(jmp_buf)); + png_memcpy(png_ptr->longjmp_buffer, tmp_jmp, png_sizeof(jmp_buf)); #endif } @@ -1451,6 +1415,9 @@ png_set_compression_strategy(png_structp png_ptr, int strategy) png_ptr->zlib_strategy = strategy; } +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ void PNGAPI png_set_compression_window_bits(png_structp png_ptr, int window_bits) { @@ -1491,6 +1458,89 @@ png_set_compression_method(png_structp png_ptr, int method) png_ptr->zlib_method = method; } +/* The following were added to libpng-1.5.4 */ +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +void PNGAPI +png_set_text_compression_level(png_structp png_ptr, int level) +{ + png_debug(1, "in png_set_text_compression_level"); + + if (png_ptr == NULL) + return; + + png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_LEVEL; + png_ptr->zlib_text_level = level; +} + +void PNGAPI +png_set_text_compression_mem_level(png_structp png_ptr, int mem_level) +{ + png_debug(1, "in png_set_text_compression_mem_level"); + + if (png_ptr == NULL) + return; + + png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_MEM_LEVEL; + png_ptr->zlib_text_mem_level = mem_level; +} + +void PNGAPI +png_set_text_compression_strategy(png_structp png_ptr, int strategy) +{ + png_debug(1, "in png_set_text_compression_strategy"); + + if (png_ptr == NULL) + return; + + png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_STRATEGY; + png_ptr->zlib_text_strategy = strategy; +} + +/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a + * smaller value of window_bits if it can do so safely. + */ +void PNGAPI +png_set_text_compression_window_bits(png_structp png_ptr, int window_bits) +{ + if (png_ptr == NULL) + return; + + if (window_bits > 15) + png_warning(png_ptr, "Only compression windows <= 32k supported by PNG"); + + else if (window_bits < 8) + png_warning(png_ptr, "Only compression windows >= 256 supported by PNG"); + +#ifndef WBITS_8_OK + /* Avoid libpng bug with 256-byte windows */ + if (window_bits == 8) + { + png_warning(png_ptr, "Text compression window is being reset to 512"); + window_bits = 9; + } + +#endif + png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS; + png_ptr->zlib_text_window_bits = window_bits; +} + +void PNGAPI +png_set_text_compression_method(png_structp png_ptr, int method) +{ + png_debug(1, "in png_set_text_compression_method"); + + if (png_ptr == NULL) + return; + + if (method != 8) + png_warning(png_ptr, "Only compression method 8 is supported by PNG"); + + png_ptr->flags |= PNG_FLAG_ZTXT_CUSTOM_METHOD; + png_ptr->zlib_text_method = method; +} +#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ +/* end of API added to libpng-1.5.4 */ + void PNGAPI png_set_write_status_fn(png_structp png_ptr, png_write_status_ptr write_row_fn) { @@ -1557,7 +1607,7 @@ png_write_png(png_structp png_ptr, png_infop info_ptr, #endif #ifdef PNG_WRITE_FILLER_SUPPORTED - /* Pack XRGB/RGBX/ARGB/RGBA into * RGB (4 channels -> 3 channels) */ + /* Pack XRGB/RGBX/ARGB/RGBA into RGB (4 channels -> 3 channels) */ if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); diff --git a/src/libpng/pngwtran.c b/src/libpng/pngwtran.c index bbf4a25b9..124d708c4 100644 --- a/src/libpng/pngwtran.c +++ b/src/libpng/pngwtran.c @@ -1,7 +1,7 @@ /* pngwtran.c - transforms the data in a row for PNG writers * - * Last changed in libpng 1.5.2 [March 31, 2011] + * Last changed in libpng 1.5.4 [July 7, 2011] * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -15,6 +15,7 @@ #ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED /* Transform the data according to the user's wishes. The order of * transformations is significant. */ @@ -45,7 +46,7 @@ png_do_write_transformations(png_structp png_ptr) #ifdef PNG_WRITE_FILLER_SUPPORTED if (png_ptr->transformations & PNG_FILLER) png_do_strip_channel(&(png_ptr->row_info), png_ptr->row_buf + 1, - !(png_ptr->flags & PNG_FILLER_AFTER)); + !(png_ptr->flags & PNG_FLAG_FILLER_AFTER)); #endif #ifdef PNG_WRITE_PACKSWAP_SUPPORTED @@ -563,6 +564,7 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) } } #endif +#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ #ifdef PNG_MNG_FEATURES_SUPPORTED /* Undoes intrapixel differencing */ diff --git a/src/libpng/pngwutil.c b/src/libpng/pngwutil.c index 2c35785aa..3ae5ed4e2 100644 --- a/src/libpng/pngwutil.c +++ b/src/libpng/pngwutil.c @@ -1,7 +1,7 @@ /* pngwutil.c - utilities to write a PNG file * - * Last changed in libpng 1.5.0 [January 6, 2011] + * Last changed in libpng 1.5.4 [July 7, 2011] * Copyright (c) 1998-2011 Glenn Randers-Pehrson * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) @@ -192,7 +192,149 @@ png_write_chunk_end(png_structp png_ptr) png_write_data(png_ptr, buf, (png_size_t)4); } -#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_iCCP_SUPPORTED) +/* Initialize the compressor for the appropriate type of compression. */ +static void +png_zlib_claim(png_structp png_ptr, png_uint_32 state) +{ + if (!(png_ptr->zlib_state & PNG_ZLIB_IN_USE)) + { + /* If already initialized for 'state' do not re-init. */ + if (png_ptr->zlib_state != state) + { + int ret = Z_OK; + png_const_charp who = "-"; + + /* If actually initialized for another state do a deflateEnd. */ + if (png_ptr->zlib_state != PNG_ZLIB_UNINITIALIZED) + { + ret = deflateEnd(&png_ptr->zstream); + who = "end"; + png_ptr->zlib_state = PNG_ZLIB_UNINITIALIZED; + } + + /* zlib itself detects an incomplete state on deflateEnd */ + if (ret == Z_OK) switch (state) + { +# ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED + case PNG_ZLIB_FOR_TEXT: + ret = deflateInit2(&png_ptr->zstream, + png_ptr->zlib_text_level, png_ptr->zlib_text_method, + png_ptr->zlib_text_window_bits, + png_ptr->zlib_text_mem_level, png_ptr->zlib_text_strategy); + who = "text"; + break; +# endif + + case PNG_ZLIB_FOR_IDAT: + ret = deflateInit2(&png_ptr->zstream, png_ptr->zlib_level, + png_ptr->zlib_method, png_ptr->zlib_window_bits, + png_ptr->zlib_mem_level, png_ptr->zlib_strategy); + who = "IDAT"; + break; + + default: + png_error(png_ptr, "invalid zlib state"); + } + + if (ret == Z_OK) + png_ptr->zlib_state = state; + + else /* an error in deflateEnd or deflateInit2 */ + { + size_t pos = 0; + char msg[64]; + + pos = png_safecat(msg, sizeof msg, pos, + "zlib failed to initialize compressor ("); + pos = png_safecat(msg, sizeof msg, pos, who); + + switch (ret) + { + case Z_VERSION_ERROR: + pos = png_safecat(msg, sizeof msg, pos, ") version error"); + break; + + case Z_STREAM_ERROR: + pos = png_safecat(msg, sizeof msg, pos, ") stream error"); + break; + + case Z_MEM_ERROR: + pos = png_safecat(msg, sizeof msg, pos, ") memory error"); + break; + + default: + pos = png_safecat(msg, sizeof msg, pos, ") unknown error"); + break; + } + + png_error(png_ptr, msg); + } + } + + /* Here on success, claim the zstream: */ + png_ptr->zlib_state |= PNG_ZLIB_IN_USE; + } + + else + png_error(png_ptr, "zstream already in use (internal error)"); +} + +/* The opposite: release the stream. It is also reset, this API will warn on + * error but will not fail. + */ +static void +png_zlib_release(png_structp png_ptr) +{ + if (png_ptr->zlib_state & PNG_ZLIB_IN_USE) + { + int ret = deflateReset(&png_ptr->zstream); + + png_ptr->zlib_state &= ~PNG_ZLIB_IN_USE; + + if (ret != Z_OK) + { + png_const_charp err; + PNG_WARNING_PARAMETERS(p) + + switch (ret) + { + case Z_VERSION_ERROR: + err = "version"; + break; + + case Z_STREAM_ERROR: + err = "stream"; + break; + + case Z_MEM_ERROR: + err = "memory"; + break; + + default: + err = "unknown"; + break; + } + + png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_d, ret); + png_warning_parameter(p, 2, err); + + if (png_ptr->zstream.msg) + err = png_ptr->zstream.msg; + else + err = "[no zlib message]"; + + png_warning_parameter(p, 3, err); + + png_formatted_warning(png_ptr, p, + "zlib failed to reset compressor: @1(@2): @3"); + } + } + + else + png_warning(png_ptr, "zstream not in use (internal error)"); +} + +#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED /* This pair of functions encapsulates the operation of (a) compressing a * text string, and (b) issuing it later as a series of chunk data writes. * The compression_state structure is shared context for these functions @@ -220,25 +362,22 @@ png_text_compress(png_structp png_ptr, comp->max_output_ptr = 0; comp->output_ptr = NULL; comp->input = NULL; - comp->input_len = 0; + comp->input_len = text_len; /* We may just want to pass the text right through */ if (compression == PNG_TEXT_COMPRESSION_NONE) { comp->input = (png_const_bytep)text; - comp->input_len = text_len; return((int)text_len); } if (compression >= PNG_TEXT_COMPRESSION_LAST) { -#ifdef PNG_CONSOLE_IO_SUPPORTED - char msg[50]; - png_snprintf(msg, 50, "Unknown compression type %d", compression); - png_warning(png_ptr, msg); -#else - png_warning(png_ptr, "Unknown compression type"); -#endif + PNG_WARNING_PARAMETERS(p) + + png_warning_parameter_signed(p, 1, PNG_NUMBER_FORMAT_d, + compression); + png_formatted_warning(png_ptr, p, "Unknown compression type @1"); } /* We can't write the chunk until we find out how much data we have, @@ -255,10 +394,12 @@ png_text_compress(png_structp png_ptr, * data, or if the input string is incredibly large (although this * wouldn't cause a failure, just a slowdown due to swapping). */ + png_zlib_claim(png_ptr, PNG_ZLIB_FOR_TEXT); /* Set up the compression buffers */ /* TODO: the following cast hides a potential overflow problem. */ png_ptr->zstream.avail_in = (uInt)text_len; + /* NOTE: assume zlib doesn't overwrite the input */ png_ptr->zstream.next_in = (Bytef *)text; png_ptr->zstream.avail_out = png_ptr->zbuf_size; @@ -418,6 +559,68 @@ png_write_compressed_data_out(png_structp png_ptr, compression_state *comp) return; } +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if (comp->input_len >= 2 && comp->input_len < 16384) + { + unsigned int z_cmf; /* zlib compression method and flags */ + + /* Optimize the CMF field in the zlib stream. This hack of the zlib + * stream is compliant to the stream specification. + */ + + if (comp->num_output_ptr) + z_cmf = comp->output_ptr[0][0]; + else + z_cmf = png_ptr->zbuf[0]; + + if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) + { + unsigned int z_cinfo; + unsigned int half_z_window_size; + png_size_t uncompressed_text_size = comp->input_len; + + z_cinfo = z_cmf >> 4; + half_z_window_size = 1 << (z_cinfo + 7); + + while (uncompressed_text_size <= half_z_window_size && + half_z_window_size >= 256) + { + z_cinfo--; + half_z_window_size >>= 1; + } + + z_cmf = (z_cmf & 0x0f) | (z_cinfo << 4); + + if (comp->num_output_ptr) + { + + if (comp->output_ptr[0][0] != z_cmf) + { + int tmp; + + comp->output_ptr[0][0] = (png_byte)z_cmf; + tmp = comp->output_ptr[0][1] & 0xe0; + tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f; + comp->output_ptr[0][1] = (png_byte)tmp; + } + } + else + { + int tmp; + + png_ptr->zbuf[0] = (png_byte)z_cmf; + tmp = png_ptr->zbuf[1] & 0xe0; + tmp += 0x1f - ((z_cmf << 8) + tmp) % 0x1f; + png_ptr->zbuf[1] = (png_byte)tmp; + } + } + + else + png_error(png_ptr, + "Invalid zlib compression method or flags in non-IDAT chunk"); + } +#endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */ + /* Write saved output buffers, if any */ for (i = 0; i < comp->num_output_ptr; i++) { @@ -436,10 +639,9 @@ png_write_compressed_data_out(png_structp png_ptr, compression_state *comp) (png_size_t)(png_ptr->zbuf_size - png_ptr->zstream.avail_out)); /* Reset zlib for another zTXt/iTXt or image data */ - deflateReset(&png_ptr->zstream); - png_ptr->zstream.data_type = Z_BINARY; + png_zlib_release(png_ptr); } -#endif +#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ /* Write the IHDR chunk, and update the png_struct with the necessary * information. Note that the rest of this code depends upon this @@ -451,7 +653,6 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, int interlace_type) { PNG_IHDR; - int ret; png_byte buf[13]; /* Buffer to store the IHDR info */ @@ -632,35 +833,35 @@ png_write_IHDR(png_structp png_ptr, png_uint_32 width, png_uint_32 height, if (!(png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_METHOD)) png_ptr->zlib_method = 8; - ret = deflateInit2(&png_ptr->zstream, png_ptr->zlib_level, - png_ptr->zlib_method, png_ptr->zlib_window_bits, - png_ptr->zlib_mem_level, png_ptr->zlib_strategy); +#ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED +#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED + if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_STRATEGY)) + png_ptr->zlib_text_strategy = Z_DEFAULT_STRATEGY; - if (ret != Z_OK) - { - if (ret == Z_VERSION_ERROR) - png_error(png_ptr, - "zlib failed to initialize compressor -- version error"); + if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_LEVEL)) + png_ptr->zlib_text_level = png_ptr->zlib_level; - if (ret == Z_STREAM_ERROR) - png_error(png_ptr, - "zlib failed to initialize compressor -- stream error"); + if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_MEM_LEVEL)) + png_ptr->zlib_text_mem_level = png_ptr->zlib_mem_level; - if (ret == Z_MEM_ERROR) - png_error(png_ptr, - "zlib failed to initialize compressor -- mem error"); + if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_WINDOW_BITS)) + png_ptr->zlib_text_window_bits = png_ptr->zlib_window_bits; - png_error(png_ptr, "zlib failed to initialize compressor"); - } + if (!(png_ptr->flags & PNG_FLAG_ZTXT_CUSTOM_METHOD)) + png_ptr->zlib_text_method = png_ptr->zlib_method; +#else + png_ptr->zlib_text_strategy = Z_DEFAULT_STRATEGY; + png_ptr->zlib_text_level = png_ptr->zlib_level; + png_ptr->zlib_text_mem_level = png_ptr->zlib_mem_level; + png_ptr->zlib_text_window_bits = png_ptr->zlib_window_bits; + png_ptr->zlib_text_method = png_ptr->zlib_method; +#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ +#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; - /* libpng is not interested in zstream.data_type, so set it - * to a predefined value, to avoid its evaluation inside zlib - */ - png_ptr->zstream.data_type = Z_BINARY; + /* Record that the compressor has not yet been initialized. */ + png_ptr->zlib_state = PNG_ZLIB_UNINITIALIZED; - png_ptr->mode = PNG_HAVE_IHDR; + png_ptr->mode = PNG_HAVE_IHDR; /* not READY_FOR_ZTXT */ } /* Write the palette. We are careful not to trust png_color to be in the @@ -745,12 +946,15 @@ png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length) png_debug(1, "in png_write_IDAT"); - /* Optimize the CMF field in the zlib stream. */ - /* This hack of the zlib stream is compliant to the stream specification. */ +#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED if (!(png_ptr->mode & PNG_HAVE_IDAT) && png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) { + /* Optimize the CMF field in the zlib stream. This hack of the zlib + * stream is compliant to the stream specification. + */ unsigned int z_cmf = data[0]; /* zlib compression method and flags */ + if ((z_cmf & 0x0f) == 8 && (z_cmf & 0xf0) <= 0x70) { /* Avoid memory underflows and multiplication overflows. @@ -761,11 +965,29 @@ png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length) if (length >= 2 && png_ptr->height < 16384 && png_ptr->width < 16384) { + /* Compute the maximum possible length of the datastream */ + + /* Number of pixels, plus for each row a filter byte + * and possibly a padding byte, so increase the maximum + * size to account for these. + */ + unsigned int z_cinfo; + unsigned int half_z_window_size; png_uint_32 uncompressed_idat_size = png_ptr->height * ((png_ptr->width * png_ptr->channels * png_ptr->bit_depth + 15) >> 3); - unsigned int z_cinfo = z_cmf >> 4; - unsigned int half_z_window_size = 1 << (z_cinfo + 7); + + /* If it's interlaced, each block of 8 rows is sent as up to + * 14 rows, i.e., 6 additional rows, each with a filter byte + * and possibly a padding byte + */ + if (png_ptr->interlaced) + uncompressed_idat_size += ((png_ptr->height + 7)/8) * + (png_ptr->bit_depth < 8 ? 12 : 6); + + z_cinfo = z_cmf >> 4; + half_z_window_size = 1 << (z_cinfo + 7); + while (uncompressed_idat_size <= half_z_window_size && half_z_window_size >= 256) { @@ -790,9 +1012,17 @@ png_write_IDAT(png_structp png_ptr, png_bytep data, png_size_t length) png_error(png_ptr, "Invalid zlib compression method or flags in IDAT"); } +#endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */ png_write_chunk(png_ptr, png_IDAT, data, length); png_ptr->mode |= PNG_HAVE_IDAT; + + /* Prior to 1.5.4 this code was replicated in every caller (except at the + * end, where it isn't technically necessary). Since this function has + * flushed the data we can safely reset the zlib output buffer here. + */ + png_ptr->zstream.next_out = png_ptr->zbuf; + png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; } /* Write an IEND chunk */ @@ -918,7 +1148,10 @@ png_write_iCCP(png_structp png_ptr, png_const_charp name, int compression_type, (png_size_t)(name_len + 2)); if (profile_len) + { + comp.input_len = profile_len; png_write_compressed_data_out(png_ptr, &comp); + } png_write_chunk_end(png_ptr); png_free(png_ptr, new_name); @@ -1313,15 +1546,11 @@ png_check_keyword(png_structp png_ptr, png_const_charp key, png_charpp new_key) if ((png_byte)*ikp < 0x20 || ((png_byte)*ikp > 0x7E && (png_byte)*ikp < 0xA1)) { -#ifdef PNG_CONSOLE_IO_SUPPORTED - char msg[40]; + PNG_WARNING_PARAMETERS(p) - png_snprintf(msg, 40, - "invalid keyword character 0x%02X", (png_byte)*ikp); - png_warning(png_ptr, msg); -#else - png_warning(png_ptr, "invalid character in keyword"); -#endif + png_warning_parameter_unsigned(p, 1, PNG_NUMBER_FORMAT_02x, + (png_byte)*ikp); + png_formatted_warning(png_ptr, p, "invalid keyword character 0x@1"); *dp = ' '; } @@ -1499,6 +1728,7 @@ png_write_zTXt(png_structp png_ptr, png_const_charp key, png_const_charp text, png_write_chunk_data(png_ptr, &buf, (png_size_t)1); /* Write the compressed data */ + comp.input_len = text_len; png_write_compressed_data_out(png_ptr, &comp); /* Close the chunk */ @@ -1871,6 +2101,7 @@ png_write_start_row(png_structp png_ptr) png_ptr->usr_width = png_ptr->width; } + png_zlib_claim(png_ptr, PNG_ZLIB_FOR_IDAT); png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; png_ptr->zstream.next_out = png_ptr->zbuf; } @@ -1992,7 +2223,7 @@ png_write_finish_row(png_structp png_ptr) png_ptr->zstream.avail_out); } - deflateReset(&png_ptr->zstream); + png_zlib_release(png_ptr); png_ptr->zstream.data_type = Z_BINARY; } @@ -2181,6 +2412,8 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) * been specified by the application, and then writes the row out with the * chosen filter. */ +static void png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row); + #define PNG_MAXSUM (((png_uint_32)(-1)) >> 1) #define PNG_HISHIFT 10 #define PNG_LOMASK ((png_uint_32)0xffffL) @@ -2856,7 +3089,7 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) /* Do the actual writing of a previously filtered row. */ -void /* PRIVATE */ +static void png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row) { png_size_t avail; @@ -2916,8 +3149,6 @@ png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row) { /* Write the IDAT and reset the zlib output buffer */ png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size); - png_ptr->zstream.next_out = png_ptr->zbuf; - png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; } /* Repeat until all data has been compressed */ } while (avail > 0 || png_ptr->zstream.avail_in > 0);