diff --git a/ANNOUNCE b/ANNOUNCE index d2c3cc82..17487381 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -78,6 +78,9 @@ version 1.2.41beta07 [October 21, 2009] many "#if defined(x)" to "#ifdef x" in png.h and pngconf.h. version 1.2.41beta08 [October 30, 2009] + Ported functions from libpng-1.4.0rc01: png_calloc(), png_get_io_state(), + png_get_io_chunk_name(), png_set_premultiply_alpha, and + png_do_read_premultiply_alpha(). Send comments/corrections/commendations to png-mng-implement at lists.sf.net diff --git a/CHANGES b/CHANGES index bacb70cc..7d3eedf4 100644 --- a/CHANGES +++ b/CHANGES @@ -2508,6 +2508,9 @@ version 1.2.41beta07 [October 21, 2009] many "#if defined(x)" to "#ifdef x" in png.h and pngconf.h. version 1.2.41beta08 [October 30, 2009] + Ported functions from libpng-1.4.0rc01: png_calloc(), png_get_io_state(), + png_get_io_chunk_name(), png_set_premultiply_alpha, and + png_do_read_premultiply_alpha(). Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/libpng-1.2.41beta08.txt b/libpng-1.2.41beta08.txt index db4ac65d..e0893171 100644 --- a/libpng-1.2.41beta08.txt +++ b/libpng-1.2.41beta08.txt @@ -882,6 +882,15 @@ images) is fully transparent, with png_set_invert_alpha(png_ptr); +The PNG format only supports pixels with postmultiplied alpha. +If you want to replace the pixels, after reading them, with pixels +that have premultiplied color samples, you can do this with + + png_set_premultiply_alpha(png_ptr); + +If you do this, any input with a tRNS chunk will be expanded to +have an alpha channel. + PNG files pack pixels of bit depths 1, 2, and 4 into bytes as small as they can, resulting in, for example, 8 pixels per byte for 1 bit files. This code expands to 1 pixel per byte without changing the @@ -2935,6 +2944,70 @@ selection of assembler code features: We replaced all of these functions with simple stubs in libpng-1.2.20, when the Intel assembler code was removed due to a licensing issue. +These macros are deprecated: + + PNG_READ_TRANSFORMS_NOT_SUPPORTED + PNG_PROGRESSIVE_READ_NOT_SUPPORTED + PNG_NO_SEQUENTIAL_READ_SUPPORTED + PNG_WRITE_TRANSFORMS_NOT_SUPPORTED + PNG_READ_ANCILLARY_CHUNKS_NOT_SUPPORTED + PNG_WRITE_ANCILLARY_CHUNKS_NOT_SUPPORTED + +They have been replaced, respectively, by: + + PNG_NO_READ_TRANSFORMS + PNG_NO_PROGRESSIVE_READ + PNG_NO_SEQUENTIAL_READ + PNG_NO_WRITE_TRANSFORMS + PNG_NO_READ_ANCILLARY_CHUNKS + PNG_NO_WRITE_ANCILLARY_CHUNKS + +PNG_MAX_UINT was replaced with PNG_UINT_31_MAX. It has been +deprecated since libpng-1.0.16 and libpng-1.2.6. + +The function + png_check_sig(sig, num) +was replaced with + !png_sig_cmp(sig, 0, num) +It has been deprecated since libpng-0.90. + +The function + png_set_gray_1_2_4_to_8() +which also expands tRNS to alpha was replaced with + png_set_expand_gray_1_2_4_to_8() +which does not. It has been deprecated since libpng-1.0.18 and 1.2.9. + +Functions png_set_benign_errors(), png_benign_error(), and +png_chunk_benign_error() were added. + +Support for setting the maximum amount of memory that the application +will allocate for reading chunks was added, as a security measure. +The functions png_set_chunk_cache_max() and png_get_chunk_cache_max() +were added to the library. + +We implemented support for I/O states. Added png_ptr member io_state, and +functions png_get_io_chunk_name() and png_get_io_state() in pngget.c + +The png_calloc() function was added and is used in place of +of "png_malloc(); png_memset();" except in the case in png_read_png() +where the array consists of pointers; in this case a "for" loop is used +after the png_malloc() to set the pointers to NULL. + +We added PNG_TRANSFORM_GRAY_TO_RGB to the available high-level +input transforms. + +We added the png_set_premultiply_alpha and +png_do_read_premultiply_alpha() functions. + +The call to png_do_chop() in pngrtran.c, which reduces 16-bit input +files to 8-bit bit depth, was relocated ahead of the building +of gamma tables. This allows us to build 8-bit tables instead +of 16-bit tables, when only 8-bit tables are needed. This avoids +wasting some computing resources when the application has called +the png_set_strip_16() function and encounters a 16-bit PNG file. + +Checking for and reporting of errors in the IHDR chunk is more thorough. + IX. (Omitted) X. Detecting libpng diff --git a/png.c b/png.c index d7cbdef0..16201a8a 100644 --- a/png.c +++ b/png.c @@ -717,10 +717,23 @@ png_charp PNGAPI png_get_copyright(png_structp png_ptr) { png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */ - return ((png_charp) "\n libpng version 1.2.41beta08 - October 30, 2009\n\ - Copyright (c) 1998-2009 Glenn Randers-Pehrson\n\ - Copyright (c) 1996-1997 Andreas Dilger\n\ - Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.\n"); +#ifdef PNG_STRING_COPYRIGHT + return PNG_STRING_COPYRIGHT +#else +#ifdef __STDC__ + return ((png_charp) PNG_STRING_NEWLINE \ + "libpng version x 1.2.41beta08 - October 30, 2009" PNG_STRING_NEWLINE \ + "Copyright (c) 1998-2009 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 ((png_charp) "libpng version 1.2.41beta08 - October 30, 2009\ + Copyright (c) 1998-2009 Glenn Randers-Pehrson\ + Copyright (c) 1996-1997 Andreas Dilger\ + Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc."); +#endif +#endif } /* The following return the library version as a short string in the @@ -752,11 +765,15 @@ png_get_header_version(png_structp png_ptr) { /* Returns longer string containing both version and date */ png_ptr = png_ptr; /* Silence compiler warning about unused png_ptr */ +#ifdef __STDC__ return ((png_charp) PNG_HEADER_VERSION_STRING #ifndef PNG_READ_SUPPORTED " (NO READ SUPPORT)" #endif - "\n"); + PNG_STRING_NEWLINE); +#else + return ((png_charp) PNG_HEADER_VERSION_STRING); +#endif } #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) diff --git a/png.h b/png.h index 30f642c2..34ccc8e2 100644 --- a/png.h +++ b/png.h @@ -1199,6 +1199,8 @@ typedef void (PNGAPI *png_unknown_chunk_ptr) PNGARG((png_structp)); /* Added to libpng-1.2.34 */ #define PNG_TRANSFORM_STRIP_FILLER_BEFORE 0x0800 /* write only */ #define PNG_TRANSFORM_STRIP_FILLER_AFTER 0x1000 /* write only */ +/* Added to libpng-1.2.41 */ +#define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */ /* Flags for MNG supported features */ #define PNG_FLAG_MNG_EMPTY_PLTE 0x01 @@ -1498,6 +1500,10 @@ struct png_struct_def #ifdef PNG_SET_USER_LIMITS_SUPPORTED png_uint_32 user_width_max; png_uint_32 user_height_max; + /* Added in libpng-1.2.41: Total number of sPLT, text, and unknown + * chunks that can be stored (0x7fffffff means unlimited). + */ + png_uint_32 user_chunk_cache_max; #endif /* New member added in libpng-1.0.25 and 1.2.17 */ @@ -1512,6 +1518,10 @@ struct png_struct_def /* New member added in libpng-1.2.30 */ png_charp chunkdata; /* buffer for reading chunk data */ +/* New member added in libpng-1.4.0 */ +#ifdef PNG_IO_STATE_SUPPORTED + png_uint_32 io_state; +#endif }; @@ -1699,6 +1709,11 @@ extern PNG_EXPORT(void,png_set_swap_alpha) PNGARG((png_structp png_ptr)); extern PNG_EXPORT(void,png_set_invert_alpha) PNGARG((png_structp png_ptr)); #endif +#ifdef PNG_READ_PREMULTIPLY_ALPHA_SUPPORTED +extern PNG_EXPORT(void,png_set_premultiply_alpha) + PNGARG((png_structp png_ptr)); +#endif + #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) /* Add a filler byte to 8-bit Gray or 24-bit RGB images. */ extern PNG_EXPORT(void,png_set_filler) PNGARG((png_structp png_ptr, @@ -2104,6 +2119,9 @@ extern PNG_EXPORT(void,png_progressive_combine_row) PNGARG((png_structp png_ptr, extern PNG_EXPORT(png_voidp,png_malloc) PNGARG((png_structp png_ptr, png_uint_32 size)); +/* Added at libpng version 1.2.41 */ +extern PNG_EXPORT(png_voidp,png_calloc) PNGARG((png_structp png_ptr, + png_uint_32 size)); #ifdef PNG_1_0_X # define png_malloc_warn png_malloc @@ -2778,6 +2796,24 @@ extern PNG_EXPORT(png_uint_32,png_get_user_height_max) PNGARG((png_structp png_ptr)); #endif +/* Added in libpng-1.4.0 */ +#ifdef PNG_IO_STATE_SUPPORTED +extern PNG_EXPORT(png_uint_32,png_get_io_state) PNGARG((png_structp png_ptr)); + +extern PNG_EXPORT(png_bytep,png_get_io_chunk_name) + PNGARG((png_structp png_ptr)); + +/* The flags returned by png_get_io_state() are the following: */ +#define PNG_IO_NONE 0x0000 /* no I/O at this moment */ +#define PNG_IO_READING 0x0001 /* currently reading */ +#define PNG_IO_WRITING 0x0002 /* currently writing */ +#define PNG_IO_SIGNATURE 0x0010 /* currently at the file signature */ +#define PNG_IO_CHUNK_HDR 0x0020 /* currently at the chunk header */ +#define PNG_IO_CHUNK_DATA 0x0040 /* currently at the chunk data */ +#define PNG_IO_CHUNK_CRC 0x0080 /* currently at the chunk crc */ +#define PNG_IO_MASK_OP 0x000f /* current operation: reading/writing */ +#define PNG_IO_MASK_LOC 0x00f0 /* current location: sig/hdr/data/crc */ +#endif /* ?PNG_IO_STATE_SUPPORTED */ /* Maintainer: Put new public prototypes here ^, in libpng.3, and in * project defs @@ -2921,7 +2957,8 @@ extern PNG_EXPORT(void,png_save_uint_16) /* 0x800000L Unused */ #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_PREMULTIPLY_ALPHA 0x4000000L /* Added to libpng-1.2.41 */ + /* by volker */ /* 0x8000000L unused */ /* 0x10000000L unused */ /* 0x20000000L unused */ @@ -3414,6 +3451,11 @@ PNG_EXTERN void png_do_strip_filler PNGARG((png_row_infop row_info, png_bytep row, png_uint_32 flags)); #endif +#ifdef PNG_READ_PREMULTIPLY_ALPHA_SUPPORTED +PNG_EXTERN void png_do_read_premultiply_alpha + PNGARG((png_row_infop row_info, png_bytep row)); +#endif + #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) PNG_EXTERN void png_do_swap PNGARG((png_row_infop row_info, png_bytep row)); #endif diff --git a/pngconf.h b/pngconf.h index 20b94f97..943f32af 100644 --- a/pngconf.h +++ b/pngconf.h @@ -115,6 +115,17 @@ # define PNG_WRITE_SUPPORTED #endif +/* Enabled in 1.2.41. */ +#ifdef PNG_ALLOW_BENIGN_ERRORS +# define png_benign_error png_warning +# define png_chunk_benign_error png_chunk_warning +#else +# ifndef PNG_BENIGN_ERRORS_SUPPORTED +# define png_benign_error png_error +# define png_chunk_benign_error png_chunk_error +# endif +#endif + /* Added in libpng-1.2.41 */ #if !defined(PNG_NO_WARNINGS) && !defined(PNG_WARNINGS_SUPPORTED) # define PNG_WARNINGS_SUPPORTED @@ -613,24 +624,33 @@ # ifndef PNG_NO_READ_BACKGROUND # define PNG_READ_BACKGROUND_SUPPORTED # endif +#ifndef PNG_1_0_X # ifndef PNG_NO_READ_16_TO_8 # define PNG_READ_16_TO_8_SUPPORTED # endif +#endif # ifndef PNG_NO_READ_FILLER # define PNG_READ_FILLER_SUPPORTED # endif # ifndef PNG_NO_READ_GAMMA # define PNG_READ_GAMMA_SUPPORTED # endif +#ifndef PNG_1_0_X # ifndef PNG_NO_READ_GRAY_TO_RGB # define PNG_READ_GRAY_TO_RGB_SUPPORTED # endif +#endif # ifndef PNG_NO_READ_SWAP_ALPHA # define PNG_READ_SWAP_ALPHA_SUPPORTED # endif # ifndef PNG_NO_READ_INVERT_ALPHA # define PNG_READ_INVERT_ALPHA_SUPPORTED # endif +#ifndef PNG_1_0_X +# ifndef PNG_NO_READ_PREMULTIPLY_ALPHA +# define PNG_READ_PREMULTIPLY_ALPHA_SUPPORTED +# endif +#endif # ifndef PNG_NO_READ_STRIP_ALPHA # define PNG_READ_STRIP_ALPHA_SUPPORTED # endif @@ -707,9 +727,11 @@ # ifndef PNG_NO_WRITE_SWAP_ALPHA # define PNG_WRITE_SWAP_ALPHA_SUPPORTED # endif +#ifndef PNG_1_0_X # ifndef PNG_NO_WRITE_INVERT_ALPHA # define PNG_WRITE_INVERT_ALPHA_SUPPORTED # endif +#endif # ifndef PNG_NO_WRITE_USER_TRANSFORM # define PNG_WRITE_USER_TRANSFORM_SUPPORTED # endif @@ -847,7 +869,31 @@ # define PNG_USER_HEIGHT_MAX 1000000L #endif -/* Added at libpng-1.2.34 and 1.4.0 */ +#ifndef PNG_1_0_X +/* Added at libpng-1.2.41 */ +#ifndef PNG_USER_CHUNK_CACHE_MAX +# define PNG_USER_CHUNK_CACHE_MAX 0x7ffffffLL +#endif +#endif + +/* Added at libpng-1.2.41 */ +#ifndef PNG_1_0_X +#if !defined(PNG_NO_IO_STATE) && !defined(PNG_IO_STATE_SUPPORTED) +# define PNG_IO_STATE_SUPPORTED +#endif +#endif + +#ifndef PNG_LITERAL_SHARP +# define PNG_LITERAL_SHARP 0x23 +#endif +#ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET +# define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b +#endif +#ifndef PNG_LITERAL_RIGHT_SQUARE_BRACKET +# define PNG_LITERAL_RIGHT_SQUARE_BRACKET 0x5d +#endif + +/* Added at libpng-1.2.34 */ #ifndef PNG_STRING_NEWLINE #define PNG_STRING_NEWLINE "\n" #endif diff --git a/pngerror.c b/pngerror.c index 73a72af2..4e336ea8 100644 --- a/pngerror.c +++ b/pngerror.c @@ -45,7 +45,7 @@ png_error(png_structp png_ptr, png_const_charp error_message) if (png_ptr->flags& (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) { - if (*error_message == '#') + if (*error_message == PNG_LITERAL_SHARP) { /* Strip "#nnnn " from beginning of error message. */ int offset; @@ -112,7 +112,7 @@ png_warning(png_structp png_ptr, png_const_charp warning_message) (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) #endif { - if (*warning_message == '#') + if (*warning_message == PNG_LITERAL_SHARP) { for (offset = 1; offset < 15; offset++) if (warning_message[offset] == ' ') @@ -127,6 +127,16 @@ png_warning(png_structp png_ptr, png_const_charp warning_message) } #endif /* PNG_WARNINGS_SUPPORTED */ +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_benign_error(png_structp png_ptr, png_const_charp error_message) +{ + if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) + png_warning(png_ptr, error_message); + else + png_error(png_ptr, error_message); +} +#endif /* These utilities are used internally to build an error message that relates * to the current chunk. The chunk name comes from png_ptr->chunk_name, @@ -153,10 +163,10 @@ png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp int c = png_ptr->chunk_name[iin++]; if (isnonalpha(c)) { - buffer[iout++] = '['; + buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET; buffer[iout++] = png_digit[(c & 0xf0) >> 4]; buffer[iout++] = png_digit[c & 0x0f]; - buffer[iout++] = ']'; + buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET; } else { @@ -206,6 +216,18 @@ png_chunk_warning(png_structp png_ptr, png_const_charp warning_message) } #endif /* PNG_WARNINGS_SUPPORTED */ +#ifdef PNG_READ_SUPPORTED +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_chunk_benign_error(png_structp png_ptr, png_const_charp error_message) +{ + if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) + png_chunk_warning(png_ptr, error_message); + else + png_chunk_error(png_ptr, error_message); +} +#endif +#endif /* PNG_READ_SUPPORTED */ /* This is the default error handling function. Note that replacements for * this function MUST NOT RETURN, or the program will likely crash. This @@ -217,7 +239,7 @@ 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 == '#') + if (*error_message == PNG_LITERAL_SHARP) { /* Strip "#nnnn " from beginning of error message. */ int offset; @@ -282,7 +304,7 @@ png_default_warning(png_structp png_ptr, png_const_charp warning_message) { #ifdef PNG_CONSOLE_IO_SUPPORTED # ifdef PNG_ERROR_NUMBERS_SUPPORTED - if (*warning_message == '#') + if (*warning_message == PNG_LITERAL_SHARP) { int offset; char warning_number[16]; diff --git a/pngget.c b/pngget.c index 1f66f6fa..08fcd22a 100644 --- a/pngget.c +++ b/pngget.c @@ -939,7 +939,27 @@ png_get_user_height_max (png_structp png_ptr) { return (png_ptr? png_ptr->user_height_max : 0); } +/* This function was added to libpng 1.2.41 */ +png_uint_32 PNGAPI +png_get_chunk_cache_max (png_structp png_ptr) +{ + return (png_ptr? png_ptr->user_chunk_cache_max? 0x7fffffffL : + png_ptr->user_chunk_cache_max - 1 : 0); +} #endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ +#ifdef PNG_IO_STATE_SUPPORTED +png_uint_32 PNGAPI +png_get_io_state (png_structp png_ptr) +{ + return png_ptr->io_state; +} + +png_bytep PNGAPI +png_get_io_chunk_name (png_structp png_ptr) +{ + return png_ptr->chunk_name; +} +#endif /* ?PNG_IO_STATE_SUPPORTED */ #endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/pngmem.c b/pngmem.c index 6d48775d..1a0a5b58 100644 --- a/pngmem.c +++ b/pngmem.c @@ -114,6 +114,16 @@ png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn, * result, we would be truncating potentially larger memory requests * (which should cause a fatal error) and introducing major problems. */ +png_voidp PNGAPI +png_calloc(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ret; + + ret = (png_malloc(png_ptr, size)); + if (ret != NULL) + png_memset(ret,0,(png_size_t)size); + return (ret); +} png_voidp PNGAPI png_malloc(png_structp png_ptr, png_uint_32 size) @@ -431,6 +441,16 @@ png_destroy_struct_2(png_voidp struct_ptr, png_free_ptr free_fn, * have the ability to do that. */ +png_voidp PNGAPI +png_calloc(png_structp png_ptr, png_uint_32 size) +{ + png_voidp ret; + + ret = (png_malloc(png_ptr, size)); + if (ret != NULL) + png_memset(ret,0,(png_size_t)size); + return (ret); +} png_voidp PNGAPI png_malloc(png_structp png_ptr, png_uint_32 size) diff --git a/pngread.c b/pngread.c index 81d3703c..5526cbe9 100644 --- a/pngread.c +++ b/pngread.c @@ -349,6 +349,10 @@ png_read_info(png_structp png_ptr, png_infop info_ptr) png_size_t num_checked = png_ptr->sig_bytes, num_to_check = 8 - num_checked; +#ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_SIGNATURE; +#endif + png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); png_ptr->sig_bytes = 8; @@ -1448,6 +1452,22 @@ png_read_png(png_structp png_ptr, png_infop info_ptr, png_set_swap(png_ptr); #endif +/* Added at libpng-1.2.41 */ +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel from opacity to transparency + */ + if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + png_set_invert_alpha(png_ptr); +#endif + +/* Added at libpng-1.2.41 */ +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* Expand grayscale image to RGB + */ + if (transforms & PNG_TRANSFORM_GRAY_TO_RGB) + png_set_gray_to_rgb(png_ptr); +#endif + /* We don't handle adding filler bytes */ /* Optional call to gamma correct and add the background to the palette diff --git a/pngrtran.c b/pngrtran.c index 2af37fd6..296993f8 100644 --- a/pngrtran.c +++ b/pngrtran.c @@ -140,6 +140,22 @@ png_set_strip_alpha(png_structp png_ptr) } #endif +#ifdef PNG_READ_PREMULTIPLY_ALPHA_SUPPORTED +void PNGAPI +png_set_premultiply_alpha(png_structp png_ptr) +{ + png_debug(1, "in png_set_premultiply_alpha"); + + if(png_ptr == NULL) + return; + png_ptr->transformations |= + (PNG_PREMULTIPLY_ALPHA | PNG_EXPAND_tRNS); + png_ptr->transformations |= + PNG_EXPAND; /* This shouldn't be necessary */ + png_ptr->flags &= ~PNG_FLAG_ROW_INIT; +} +#endif + #ifdef PNG_READ_DITHER_SUPPORTED /* Dither file to 8 bit. Supply a palette, the current number * of elements in the palette, the maximum number of elements @@ -335,9 +351,8 @@ png_set_dither(png_structp png_ptr, png_colorp palette, png_ptr->palette_to_index[i] = (png_byte)i; } - hash = (png_dsortpp)png_malloc(png_ptr, (png_uint_32)(769 * + hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 * png_sizeof(png_dsortp))); - png_memset(hash, 0, 769 * png_sizeof(png_dsortp)); num_new_palette = num_palette; @@ -483,10 +498,9 @@ png_set_dither(png_structp png_ptr, png_colorp palette, int num_green = (1 << PNG_DITHER_GREEN_BITS); int num_blue = (1 << PNG_DITHER_BLUE_BITS); png_size_t num_entries = ((png_size_t)1 << total_bits); - png_ptr->palette_lookup = (png_bytep )png_malloc(png_ptr, + + png_ptr->palette_lookup = (png_bytep )png_calloc(png_ptr, (png_uint_32)(num_entries * png_sizeof(png_byte))); - png_memset(png_ptr->palette_lookup, 0, num_entries * - png_sizeof(png_byte)); distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries * png_sizeof(png_byte))); @@ -1437,6 +1451,11 @@ 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_16_TO_8_SUPPORTED + if (png_ptr->transformations & PNG_16_TO_8) + png_do_chop(&(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 ) || @@ -1466,11 +1485,6 @@ png_do_read_transformations(png_structp png_ptr) png_ptr->gamma_shift); #endif -#ifdef PNG_READ_16_TO_8_SUPPORTED - if (png_ptr->transformations & PNG_16_TO_8) - png_do_chop(&(png_ptr->row_info), png_ptr->row_buf + 1); -#endif - #ifdef PNG_READ_DITHER_SUPPORTED if (png_ptr->transformations & PNG_DITHER) { @@ -1520,6 +1534,12 @@ png_do_read_transformations(png_structp png_ptr) (png_uint_32)png_ptr->filler, png_ptr->flags); #endif +#ifdef PNG_READ_PREMULTIPLY_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_PREMULTIPLY_ALPHA) + png_do_read_premultiply_alpha(&(png_ptr->row_info), + png_ptr->row_buf + 1); +#endif + #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED if (png_ptr->transformations & PNG_INVERT_ALPHA) png_do_read_invert_alpha(&(png_ptr->row_info), png_ptr->row_buf + 1); @@ -2023,6 +2043,85 @@ png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) } #endif +#ifdef PNG_READ_PREMULTIPLY_ALPHA_SUPPORTED +void /* PRIVATE */ +png_do_read_premultiply_alpha(png_row_infop row_info, png_bytep row) +{ + png_debug(1, "in png_do_read_premultiply_alpha"); + + { + png_uint_32 row_width = row_info->width; + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + { + /* This premultiplies the pixels with the alpha channel in RGBA */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_16 a = 0; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + a = *(--sp); --dp; + + *(--dp) = (*(--sp) * a) / 255; + *(--dp) = (*(--sp) * a) / 255; + *(--dp) = (*(--sp) * a) / 255; + } + } + /* This premultiplies the pixels with the alpha channel in RRGGBBAA */ + else + { + png_uint_16p sp = (png_uint_16p)(row + row_info->rowbytes); + png_uint_16p dp = sp; + png_uint_32 a = 0; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + a = *(--sp); --dp; + *(--dp) = (png_uint_16) ((*(--sp) * a) / 65535); + *(--dp) = (png_uint_16) ((*(--sp) * a) / 65535); + *(--dp) = (png_uint_16) ((*(--sp) * a) / 65535); + } + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This premultiplies the pixels with the alpha channel in GA */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_uint_16 a = 0; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + a = *(--sp); --dp; + *(--dp) = (*(--sp) * a) / 255; + } + } + /* This premultiplies the pixels with the alpha channel in GGAA */ + else + { + png_uint_16p sp = (png_uint_16p) (row + row_info->rowbytes); + png_uint_16p dp = sp; + png_uint_32 a = 0; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + a = *(--sp); --dp; + *(--dp) = (png_uint_16) ((*(--sp) * a) / 65535); + } + } + } + } +} +#endif + #ifdef PNG_READ_FILLER_SUPPORTED /* Add filler channel if we have RGB color */ void /* PRIVATE */ @@ -4129,6 +4228,33 @@ static PNG_CONST int png_gamma_shift[] = * tables, we don't make a full table if we are reducing to 8-bit in * the future. Note also how the gamma_16 tables are segmented so that * we don't need to allocate > 64K chunks for a full 16-bit table. + * + * See the PNG extensions document for an integer algorithm for creating + * the gamma tables. Maybe we will implement that here someday. + * + * We should only reach this point if + * + * the file_gamma is known (i.e., the gAMA or sRGB chunk is present, + * or the application has provided a file_gamma) + * + * AND + * { + * the screen_gamma is known + * OR + * + * RGB_to_gray transformation is being performed + * } + * + * AND + * { + * the screen_gamma is different from the reciprocal of the + * file_gamma by more than the specified threshold + * + * OR + * + * a background color has been specified and the file_gamma + * and screen_gamma are not 1.0, within the specified threshold. + * } */ void /* PRIVATE */ @@ -4240,9 +4366,8 @@ png_build_gamma_table(png_structp png_ptr) else g = 1.0; - png_ptr->gamma_16_table = (png_uint_16pp)png_malloc(png_ptr, + png_ptr->gamma_16_table = (png_uint_16pp)png_calloc(png_ptr, (png_uint_32)(num * png_sizeof(png_uint_16p))); - png_memset(png_ptr->gamma_16_table, 0, num * png_sizeof(png_uint_16p)); if (png_ptr->transformations & (PNG_16_TO_8 | PNG_BACKGROUND)) { @@ -4302,9 +4427,8 @@ png_build_gamma_table(png_structp png_ptr) g = 1.0 / (png_ptr->gamma); - png_ptr->gamma_16_to_1 = (png_uint_16pp)png_malloc(png_ptr, + png_ptr->gamma_16_to_1 = (png_uint_16pp)png_calloc(png_ptr, (png_uint_32)(num * png_sizeof(png_uint_16p ))); - png_memset(png_ptr->gamma_16_to_1, 0, num * png_sizeof(png_uint_16p)); for (i = 0; i < num; i++) { @@ -4327,10 +4451,8 @@ png_build_gamma_table(png_structp png_ptr) else g = png_ptr->gamma; /* Probably doing rgb_to_gray */ - png_ptr->gamma_16_from_1 = (png_uint_16pp)png_malloc(png_ptr, + png_ptr->gamma_16_from_1 = (png_uint_16pp)png_calloc(png_ptr, (png_uint_32)(num * png_sizeof(png_uint_16p))); - png_memset(png_ptr->gamma_16_from_1, 0, - num * png_sizeof(png_uint_16p)); for (i = 0; i < num; i++) { diff --git a/pngrutil.c b/pngrutil.c index 15bac985..a696db80 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -112,6 +112,13 @@ png_read_chunk_header(png_structp png_ptr) png_byte buf[8]; png_uint_32 length; +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the chunk header is being read. + * PNG_IO_CHUNK_HDR requires a single I/O call. + */ + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR; +#endif + /* Read the length and the chunk name */ png_read_data(png_ptr, buf, 8); length = png_get_uint_31(png_ptr, buf); @@ -129,6 +136,13 @@ png_read_chunk_header(png_structp png_ptr) /* Check to see if chunk name is valid */ png_check_chunk_name(png_ptr, png_ptr->chunk_name); +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that chunk data will (possibly) be read. + * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls. + */ + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA; +#endif + return length; } @@ -203,6 +217,12 @@ png_crc_error(png_structp png_ptr) need_crc = 0; } +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the chunk CRC is being read */ + /* PNG_IO_CHUNK_CRC requires the I/O to be done at once */ + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC; +#endif + png_read_data(png_ptr, crc_bytes, 4); if (need_crc) @@ -1136,6 +1156,23 @@ png_handle_sPLT(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug(1, "in png_handle_sPLT"); +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for sPLT"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before sPLT"); @@ -1923,6 +1960,22 @@ png_handle_tEXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug(1, "in png_handle_tEXt"); +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for tEXt"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before tEXt"); @@ -2009,6 +2062,22 @@ png_handle_zTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug(1, "in png_handle_zTXt"); +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for zTXt"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before zTXt"); @@ -2114,6 +2183,22 @@ png_handle_iTXt(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug(1, "in png_handle_iTXt"); +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for iTXt"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before iTXt"); @@ -2242,6 +2327,22 @@ png_handle_unknown(png_structp png_ptr, png_infop info_ptr, png_uint_32 length) png_debug(1, "in png_handle_unknown"); +#ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (png_ptr->user_chunk_cache_max != 0) + { + if (png_ptr->user_chunk_cache_max == 1) + { + png_crc_finish(png_ptr, length); + return; + } + if (--png_ptr->user_chunk_cache_max == 1) + { + png_warning(png_ptr, "No space in chunk cache for unknown chunk"); + png_crc_finish(png_ptr, length); + return; + } + } +#endif if (png_ptr->mode & PNG_HAVE_IDAT) { @@ -3209,9 +3310,10 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) if (row_bytes + 64 > png_ptr->old_big_row_buf_size) { png_free(png_ptr, png_ptr->big_row_buf); - png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 64); if (png_ptr->interlaced) - png_memset(png_ptr->big_row_buf, 0, row_bytes + 64); + png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr, row_bytes + 64); + else + png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 64); png_ptr->row_buf = png_ptr->big_row_buf + 32; png_ptr->old_big_row_buf_size = row_bytes + 64; } diff --git a/pngset.c b/pngset.c index d98437d4..200a1f46 100644 --- a/pngset.c +++ b/pngset.c @@ -474,10 +474,8 @@ png_set_PLTE(png_structp png_ptr, png_infop info_ptr, * of num_palette entries, in case of an invalid PNG file that has * too-large sample values. */ - png_ptr->palette = (png_colorp)png_malloc(png_ptr, + png_ptr->palette = (png_colorp)png_calloc(png_ptr, PNG_MAX_PALETTE_LENGTH * png_sizeof(png_color)); - png_memset(png_ptr->palette, 0, PNG_MAX_PALETTE_LENGTH * - png_sizeof(png_color)); png_memcpy(png_ptr->palette, palette, num_palette * png_sizeof(png_color)); info_ptr->palette = png_ptr->palette; info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; @@ -1208,7 +1206,33 @@ png_set_user_limits (png_structp png_ptr, png_uint_32 user_width_max, png_ptr->user_width_max = user_width_max; png_ptr->user_height_max = user_height_max; } +/* This function was added to libpng 1.2.41 */ +void PNGAPI +png_set_chunk_cache_max (png_structp png_ptr, + png_uint_32 user_chunk_cache_max) +{ + if (png_ptr == NULL) + return; + png_ptr->user_chunk_cache_max = user_chunk_cache_max; + if (user_chunk_cache_max == 0x7fffffffL) /* Unlimited */ + png_ptr->user_chunk_cache_max = 0; + else + png_ptr->user_chunk_cache_max = user_chunk_cache_max + 1; +} #endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ + +#ifdef PNG_BENIGN_ERRORS_SUPPORTED +void PNGAPI +png_set_benign_errors(png_structp png_ptr, int allowed) +{ + png_debug(1, "in png_set_benign_errors"); + + if (allowed) + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; + else + png_ptr->flags &= ~PNG_FLAG_BENIGN_ERRORS_WARN; +} +#endif /* PNG_BENIGN_ERRORS_SUPPORTED */ #endif /* ?PNG_1_0_X */ #endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/pngwrite.c b/pngwrite.c index 1bad46c1..fb9ea8a3 100644 --- a/pngwrite.c +++ b/pngwrite.c @@ -1506,11 +1506,6 @@ png_write_png(png_structp png_ptr, png_infop info_ptr, { if (png_ptr == NULL || info_ptr == NULL) return; -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED - /* Invert the alpha channel from opacity to transparency */ - if (transforms & PNG_TRANSFORM_INVERT_ALPHA) - png_set_invert_alpha(png_ptr); -#endif /* Write the file header information. */ png_write_info(png_ptr, info_ptr); @@ -1570,6 +1565,18 @@ png_write_png(png_structp png_ptr, png_infop info_ptr, png_set_packswap(png_ptr); #endif +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel from opacity to transparency */ + if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + png_set_invert_alpha(png_ptr); +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel from opacity to transparency */ + if (transforms & PNG_TRANSFORM_INVERT_ALPHA) + png_set_invert_alpha(png_ptr); +#endif + /* ----------------------- end of transformations ------------------- */ /* Write the bits */ diff --git a/pngwutil.c b/pngwutil.c index 634d8fe4..a3faf2a7 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -58,11 +58,16 @@ png_save_uint_16(png_bytep buf, unsigned int i) * we should call png_set_sig_bytes() to tell libpng how many of the * bytes have already been written. */ -void /* PRIVATE */ +void PNGAPI png_write_sig(png_structp png_ptr) { png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the signature is being written */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_SIGNATURE; +#endif + /* Write the rest of the 8 byte signature */ png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], (png_size_t)(8 - png_ptr->sig_bytes)); @@ -106,6 +111,13 @@ png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name, if (png_ptr == NULL) return; +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the chunk header is being written. + * PNG_IO_CHUNK_HDR requires a single I/O call. + */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_HDR; +#endif + /* Write the length and the chunk name */ png_save_uint_32(buf, length); png_memcpy(buf + 4, chunk_name, 4); @@ -115,6 +127,13 @@ png_write_chunk_start(png_structp png_ptr, png_bytep chunk_name, /* Reset the crc and run it over the chunk name */ png_reset_crc(png_ptr); png_calculate_crc(png_ptr, chunk_name, (png_size_t)4); + +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that chunk data will (possibly) be written. + * PNG_IO_CHUNK_DATA does NOT require a specific number of I/O calls. + */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_DATA; +#endif } /* Write the data of a PNG chunk started with png_write_chunk_start(). @@ -146,6 +165,13 @@ png_write_chunk_end(png_structp png_ptr) if (png_ptr == NULL) return; +#ifdef PNG_IO_STATE_SUPPORTED + /* Inform the I/O callback that the chunk CRC is being written. + * PNG_IO_CHUNK_CRC requires a single I/O function call. + */ + png_ptr->io_state = PNG_IO_WRITING | PNG_IO_CHUNK_CRC; +#endif + /* Write the crc in a single operation */ png_save_uint_32(buf, png_ptr->crc); @@ -1792,29 +1818,28 @@ png_write_start_row(png_structp png_ptr) /* We only need to keep the previous row if we are using one of these. */ if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) { - /* Set up previous row buffer */ - png_ptr->prev_row = (png_bytep)png_malloc(png_ptr, - (png_uint_32)buf_size); - png_memset(png_ptr->prev_row, 0, buf_size); + /* Set up previous row buffer */ + png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, + (png_uint_32)buf_size); if (png_ptr->do_filter & PNG_FILTER_UP) { png_ptr->up_row = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(png_ptr->rowbytes + 1)); + (png_uint_32)(png_ptr->rowbytes + 1)); png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; } if (png_ptr->do_filter & PNG_FILTER_AVG) { png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(png_ptr->rowbytes + 1)); + (png_uint_32)(png_ptr->rowbytes + 1)); png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; } if (png_ptr->do_filter & PNG_FILTER_PAETH) { png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, - (png_uint_32)(png_ptr->rowbytes + 1)); + (png_uint_32)(png_ptr->rowbytes + 1)); png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; } } @@ -2151,6 +2176,14 @@ png_write_find_filter(png_structp png_ptr, png_row_infop row_info) png_debug(1, "in png_write_find_filter"); +#ifndef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->row_number == 0 && filter_to_do == PNG_ALL_FILTERS) + { + /* These will never be selected so we need not test them. */ + filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH); + } +#endif + /* Find out how many bytes offset each pixel is */ bpp = (row_info->pixel_depth + 7) >> 3; diff --git a/scripts/pngos2.def b/scripts/pngos2.def index aae310f5..d5a747ae 100644 --- a/scripts/pngos2.def +++ b/scripts/pngos2.def @@ -222,6 +222,18 @@ EXPORTS png_save_int_32 png_get_uint_31 png_set_expand_gray_1_2_4_to_8 +; Added at version 1.2.41 + png_write_sig + png_benign_error + png_benign_chunk_error + png_set_benign_error + png_get_io_chunk_name + png_get_io_state + png_set_premultiply_alpha + png_get_chunk_cache_max + png_set_chunk_cache_max + png_check_cHRM_fixed + png_calloc ; These are not present when libpng is compiled with PNG_NO_GLOBAL_ARRAYS png_pass_start diff --git a/scripts/pngw32.def b/scripts/pngw32.def index 428c58a3..3eee23de 100644 --- a/scripts/pngw32.def +++ b/scripts/pngw32.def @@ -237,3 +237,15 @@ EXPORTS png_save_int_32 @205 png_get_uint_31 @206 png_set_expand_gray_1_2_4_to_8 @207 +; Added at version 1.2.41 + png_write_sig @207 + png_benign_error @208 + png_benign_chunk_error @209 + png_set_benign_error @210 + png_get_io_chunk_name @211 + png_get_io_state @212 + png_set_premultiply_alpha @213 + png_get_chunk_cache_max @214 + png_set_chunk_cache_max @215 + png_check_cHRM_fixed @216 + png_calloc @217