diff --git a/Makefile.am b/Makefile.am index 6f07c5bea..ea4e5c086 100644 --- a/Makefile.am +++ b/Makefile.am @@ -277,7 +277,8 @@ scripts/symbols.chk: scripts/checksym.awk scripts/symbols.def scripts/symbols.ou scripts/pnglibconf.c: scripts/pnglibconf.dfa scripts/options.awk pngconf.h rm -f $@ pnglibconf.tf[67] test -z "$(CPPFLAGS)" -a -z "$(AM_CPPFLAGS)" - echo "com libpng @PNGLIB_VERSION@ STANDARD API DEFINITION" |\ + (echo "com libpng @PNGLIB_VERSION@ STANDARD API DEFINITION";\ + echo "com") |\ $(AWK) -f ${srcdir}/scripts/options.awk out=pnglibconf.tf6\ logunsupported=1 version=search ${srcdir}/pngconf.h -\ ${srcdir}/scripts/pnglibconf.dfa 1>&2 diff --git a/contrib/examples/pngcp.c b/contrib/examples/pngcp.c index ebd13d76d..6e71330a3 100644 --- a/contrib/examples/pngcp.c +++ b/contrib/examples/pngcp.c @@ -114,13 +114,30 @@ static const struct value_list const char *name; /* the command line name of the value */ int value; /* the actual value to use */ } + +#ifdef PNG_SW_COMPRESS_png_level +vl_compression[] = +{ + /* Overall compression control. The order controls the search order for + * 'all'. Since the search is for the smallest the order used is low memory + * then high speed. + */ + { "low-memory", PNG_COMPRESSION_LOW_MEMORY }, + { "high-speed", PNG_COMPRESSION_HIGH_SPEED }, + { "high-read-speed", PNG_COMPRESSION_HIGH_READ_SPEED }, + { "low", PNG_COMPRESSION_LOW }, + { "medium", PNG_COMPRESSION_MEDIUM }, + { "old", PNG_COMPRESSION_COMPAT }, + { "high", PNG_COMPRESSION_HIGH }, + { all, 0 } +}, +#endif /* SW_COMPRESS_png_level */ + #if defined(PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED) ||\ defined(PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED) vl_strategy[] = { - /* This controls the order of search and also the default (which is RLE - * compression): - */ + /* This controls the order of search. */ { "huffman", Z_HUFFMAN_ONLY }, { "RLE", Z_RLE }, { "fixed", Z_FIXED }, /* the remainder do window searchs */ @@ -172,29 +189,16 @@ vl_filter[] = { "paeth", PNG_FILTER_PAETH } }, #endif /* WRITE_FILTER */ -#define SELECT_HEURISTICALLY 1 -#define SELECT_METHODICALLY 2 -#if defined(PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED) ||\ - defined(PNG_SELECT_FILTER_METHODICALLY_SUPPORTED) -vl_select[] = -{ - { all, SELECT_HEURISTICALLY|SELECT_METHODICALLY }, - { "off", 0 }, -#ifdef PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED - { "heuristically", SELECT_HEURISTICALLY }, -#endif /* SELECT_FILTER_HEURISTICALLY */ -#ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED - { "methodically", SELECT_METHODICALLY }, -#endif /* SELECT_FILTER_METHODICALLY */ - { "both", SELECT_HEURISTICALLY|SELECT_METHODICALLY } -}, -#endif /* SELECT_FILTER_HEURISTICALLY || SELECT_FILTER_METHODICALLY */ -vl_IDAT_size[] = /* for png_set_compression_buffer_size */ +vl_IDAT_size[] = /* for png_set_IDAT_size */ { { "default", 0x7FFFFFFF }, { "minimal", 1 }, RANGE(1, 0x7FFFFFFF) }, +#ifndef PNG_SW_IDAT_size + /* Pre 1.7 API: */ +# define png_set_IDAT_size(p,v) png_set_compression_buffer_size(p, v) +#endif /* !SW_IDAT_size */ #define SL 8 /* stack limit in display, below */ vl_log_depth[] = { { "on", 1 }, { "off", 0 }, RANGE(0, SL) }, vl_on_off[] = { { "on", 1 }, { "off", 2 } }; @@ -244,8 +248,14 @@ static const struct option # ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED # define VLCIDAT(name) VLO(#name, name, 1/*search*/) +# ifdef PNG_SW_COMPRESS_level +# define VLCiCCP(name) VLO("ICC-profile-" #name, name, 0/*search*/) +# else +# define VLCiCCP(name) +# endif # else # define VLCIDAT(name) +# define VLCiCCP(name) # endif /* WRITE_CUSTOMIZE_COMPRESSION */ # ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED @@ -254,10 +264,21 @@ static const struct option # define VLCzTXt(name) # endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ -# define VLC(name) VLCIDAT(name) VLCzTXt(name) +# define VLC(name) VLCIDAT(name) VLCiCCP(name) VLCzTXt(name) +# ifdef PNG_SW_COMPRESS_png_level + /* The libpng compression level isn't searched beause it justs sets the + * other things that are searched! + */ + VLO("compression", compression, 0) + VLO("text-compression", compression, 0) + VLO("ICC-profile-compression", compression, 0) +# endif /* SW_COMPRESS_png_level */ VLC(strategy) VLO("windowBits", windowBits_IDAT, 1) +# ifdef PNG_SW_COMPRESS_windowBits + VLO("ICC-profile-windowBits", windowBits_text/*sic*/, 0) +# endif VLO("text-windowBits", windowBits_text, 0) VLC(level) VLC(memLevel) @@ -268,10 +289,6 @@ static const struct option /* LIST settings */ # define VLL(name, search) VL(#name, name, LIST, search) -#if defined(PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED) ||\ - defined(PNG_SELECT_FILTER_METHODICALLY_SUPPORTED) - VLL(select, 1) -#endif /* SELECT_FILTER_HEURISTICALLY || SELECT_FILTER_METHODICALLY */ #ifdef PNG_WRITE_FILTER_SUPPORTED VLL(filter, 0) #endif /* WRITE_FILTER */ @@ -1176,17 +1193,6 @@ getsearchopts(struct display *dp, const char *opt_str, int *value) istrat = OPTIND(dp, strategy); entry_name = range_lo; /* record the value, not the name */ -#if defined(PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED) ||\ - defined(PNG_SELECT_FILTER_METHODICALLY_SUPPORTED) - if (opt == OPTIND(dp, select)) - { - dp->value[opt] = SELECT_METHODICALLY; /* should probably be all */ - entry_name = "methodically"; /* for the moment */ - } - - else -#endif /* SELECT_FILTER_HEURISTICALLY || SELECT_FILTER_METHODICALLY */ - if (opt == istrat) /* search all strategies */ (void)advance_opt(dp, opt, 0/*iterate*/), record=0; @@ -1750,9 +1756,25 @@ set_compression(struct display *dp) SET_COMPRESSION # undef SET } + +#ifdef PNG_SW_COMPRESS_level /* 1.7.0+ */ +static void +set_ICC_profile_compression(struct display *dp) +{ + int val; + +# define SET(name, func) if (getallopts(dp, "ICC-profile-" #name, &val))\ + png_set_ICC_profile_compression_ ## func(dp->write_pp, val); + SET_COMPRESSION +# undef SET +} +#else +# define set_ICC_profile_compression(dp) ((void)0) +#endif #else # define search_compression(dp) ((void)0) # define set_compression(dp) ((void)0) +# define set_ICC_profile_compression(dp) ((void)0) #endif /* WRITE_CUSTOMIZE_COMPRESSION */ #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED @@ -1808,10 +1830,28 @@ write_png(struct display *dp, const char *destname) /* compression outputs, IDAT and zTXt/iTXt: */ dp->tsp = dp->nsp; dp->nsp = dp->csp = 0; +# ifdef PNG_SW_COMPRESS_png_level + { + int val; + + /* This sets everything, but then the following options just override + * the specific settings for ICC profiles and text. + */ + if (getallopts(dp, "compression", &val)) + png_set_compression(dp->write_pp, val); + + if (getallopts(dp, "ICC-profile-compression", &val)) + png_set_ICC_profile_compression(dp->write_pp, val); + + if (getallopts(dp, "text-compression", &val)) + png_set_text_compression(dp->write_pp, val); + } +# endif /* png_level support */ if (dp->options & SEARCH) search_compression(dp); else set_compression(dp); + set_ICC_profile_compression(dp); set_text_compression(dp); { @@ -1819,30 +1859,10 @@ write_png(struct display *dp, const char *destname) /* The permitted range is 1..0x7FFFFFFF, so the cast is safe */ if (getopt(dp, "IDAT-size", &val)) - png_set_compression_buffer_size(dp->write_pp, - (png_alloc_size_t)/*SAFE*/val); + png_set_IDAT_size(dp->write_pp, val); } /* filter handling */ -#if defined(PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED) ||\ - defined(PNG_SELECT_FILTER_METHODICALLY_SUPPORTED) - { - int val; - - if (getopt(dp, "select", &val)) - { -# ifdef PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED - png_set_option(dp->write_pp, PNG_SELECT_FILTER_HEURISTICALLY, - (val & SELECT_HEURISTICALLY) != 0); -# endif /* SELECT_FILTER_HEURISTICALLY */ -# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED - png_set_option(dp->write_pp, PNG_SELECT_FILTER_METHODICALLY, - (val & SELECT_METHODICALLY) != 0); -# endif /* SELECT_FILTER_METHODICALLY */ - } - } -#endif /* SELECT_FILTER_HEURISTICALLY || SELECT_FILTER_METHODICALLY */ - # ifdef PNG_WRITE_FILTER_SUPPORTED { int val; diff --git a/png.c b/png.c index 3dbbbb7ba..eb96a9913 100644 --- a/png.c +++ b/png.c @@ -100,10 +100,26 @@ png_zfree(voidpf png_ptr, voidpf ptr) * in case CRC is > 32 bits to leave the top bits 0. */ void /* PRIVATE */ -png_reset_crc(png_structrp png_ptr) +png_reset_crc(png_structrp png_ptr, png_const_bytep chunk_tag) { - /* The cast is safe because the crc is a 32 bit value. */ - png_ptr->crc = (png_uint_32)crc32(0, Z_NULL, 0); +# ifdef PNG_READ_SUPPORTED + if (png_ptr->read_struct) + { + /* Set png_struct::current_crc appropriately. */ + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name)) + png_ptr->current_crc = png_ptr->ancillary_crc; + + else /* critical */ + png_ptr->current_crc = png_ptr->critical_crc; + } + + else + png_ptr->current_crc = crc_error_quit; /* for write */ + + /* Now do not calculate the CRC if it isn't required: */ + if (png_ptr->current_crc != crc_quiet_use) +# endif /* READ */ + png_ptr->crc = 0xFFFFFFFFU & crc32(0, chunk_tag, 4); } /* Calculate the CRC over a section of data. We can only pass as @@ -114,27 +130,15 @@ png_reset_crc(png_structrp png_ptr) void /* PRIVATE */ png_calculate_crc(png_structrp png_ptr, png_const_voidp ptr, png_size_t length) { - int need_crc = 1; - - if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0) - { - if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == - (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) - need_crc = 0; - } - - else /* critical */ - { - if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0) - need_crc = 0; - } - /* 'uLong' is defined in zlib.h as unsigned long; this means that on some * systems it is a 64 bit value. crc32, however, returns 32 bits so the * following cast is safe. 'uInt' may be no more than 16 bits, so it is * necessary to perform a loop here. */ - if (need_crc != 0 && length > 0) +# ifdef PNG_READ_SUPPORTED + if (png_ptr->current_crc != crc_quiet_use) +# endif /* READ */ + if (length > 0) { uLong crc = png_ptr->crc; /* Should never issue a warning */ const Bytef* rptr = png_voidcast(const Bytef*,ptr); @@ -213,11 +217,6 @@ png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver) png_warning(png_ptr, m); #endif - -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - png_ptr->flags = 0; -#endif - return 0; } @@ -2192,13 +2191,12 @@ png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr, #endif unsigned int i; -#ifdef PNG_SET_OPTION_SUPPORTED - /* First see if PNG_SKIP_sRGB_CHECK_PROFILE has been set to "on" */ - if (((png_ptr->options >> PNG_SKIP_sRGB_CHECK_PROFILE) & 3) == - PNG_OPTION_ON) - return 0; -#endif - +# ifdef PNG_SET_OPTION_SUPPORTED +# ifdef PNG_SKIP_sRGB_CHECK_PROFILE + /* First see if PNG_SKIP_sRGB_CHECK_PROFILE has been set to "on" */ + if (!png_ptr->skip_sRGB_profile_check) +# endif /* SKIP_sRGB_CHECK_PROFILE */ +# endif /* SET_OPTION */ for (i=0; i < (sizeof png_sRGB_checks) / (sizeof png_sRGB_checks[0]); ++i) { if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] && @@ -3355,67 +3353,128 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times, } #endif /* GAMMA || INCH_CONVERSIONS */ -/* HARDWARE OPTION SUPPORT */ -#ifdef PNG_SET_OPTION_SUPPORTED -int PNGAPI -png_set_option(png_structrp png_ptr, int option, int onoff) -{ - if (png_ptr != NULL && option >= 0 && option < PNG_OPTION_NEXT && - (option & 1) == 0) - { - unsigned int mask = 3U << option; - unsigned int setting = (2U + (onoff != 0)) << option; - unsigned int current = png_ptr->options; - - png_ptr->options = (current & ~mask) | setting; - - return (current & mask) >> option; - } - - return PNG_OPTION_INVALID; -} -#endif /* SET_OPTION */ - /* SOFTWARE SETTING SUPPORT */ -#ifdef PNG_SETTING_SUPPORTED png_int_32 PNGAPI -png_setting(png_structrp png_ptr, int setting, png_int_32 value) +png_setting(png_structrp png_ptr, png_uint_32 setting, png_uint_32 parameter, + png_int_32 value) { - switch (setting) + png_int_32 result; + + if (png_ptr != NULL) { -# ifdef PNG_READ_GAMMA_SUPPORTED - case PNG_GAMMA_MINIMUM: - if (value < 0 || value > 0xFFFF) - value = PNG_GAMMA_THRESHOLD_FIXED; + int handle_error = (setting & PNG_SF_ERROR) != 0U; + + setting &= ~PNG_SF_ERROR; /* because it is handled below. */ + + switch (setting & (PNG_SF_READ|PNG_SF_WRITE)) + { +# ifdef PNG_READ_SUPPORTED + case PNG_SF_READ: + if (png_ptr->read_struct) + result = png_read_setting(png_ptr, setting, parameter, value); + + else + result = PNG_EINVAL; /* read setting on write struct */ + break; +# endif /* READ */ + +# ifdef PNG_WRITE_SUPPORTED + case PNG_SF_WRITE: + if (!png_ptr->read_struct) + result = png_write_setting(png_ptr, setting, parameter, + value); + + else + result = PNG_EINVAL; /* write setting on read struct */ + break; +# endif /* WRITE */ + + default: + /* Handle everything else here. This includes the error of not + * having either read or write set; that error will cause a + * PNG_ENOSYS return code. + */ + switch (setting) { - png_int_32 old = png_ptr->gamma_threshold; - png_ptr->gamma_threshold = PNG_UINT_16(value); - return old; +# ifdef PNG_SET_OPTION_SUPPORTED + case PNG_SRW_OPTION: + if (parameter >= PNG_OPTION_NEXT) + return PNG_OPTION_INVALID; + + if (parameter == PNG_SKIP_sRGB_CHECK_PROFILE) + { + if (png_ptr->skip_sRGB_profile_check) + { + if (!value) + png_ptr->skip_sRGB_profile_check = 0U; + result = PNG_OPTION_ON; + } + + else + { + if (value) + png_ptr->skip_sRGB_profile_check = 1U; + result = PNG_OPTION_OFF; + } + + break; + } + +# ifdef PNG_READ_SUPPORTED + if (png_ptr->read_struct) + { + result = png_read_setting(png_ptr, setting, + parameter, value); + break; + } +# endif /* READ */ + + /* No write options at present */ + result = PNG_OPTION_UNSET; /* i.e. ignore it */ +# endif /* SET_OPTION */ + + default: + /* Any other option; handle in the appropriate setting: */ +# ifdef PNG_READ_SUPPORTED + if (png_ptr->read_struct) + { + result = png_read_setting(png_ptr, setting, + parameter, value); + break; + } +# endif /* READ */ + +# ifdef PNG_WRITE_SUPPORTED + if (!png_ptr->read_struct) + { + result = png_write_setting(png_ptr, setting, + parameter, value); + break; + } +# endif /* WRITE */ + + NOT_REACHED; + result= PNG_ENOSYS; + break; } break; + } /* switch */ -#if 0 /*NYI*/ - case PNG_GAMMA_ACCURACY: - if (value < 0 || value > 1600) - value = PNG_DEFAULT_GAMMA_ACCURACY; - { - png_int_32 old = png_ptr->gamma_accuracy; - png_ptr->gamma_accuracy = value; - return old; - } - break; -#endif /*NYI*/ -# endif /* READ_GAMMA */ - - default: - break; + /* Handle error returns here. + * TODO: this is crude, should use a formatted warning style message and + * output result/setting/parameter/value. + */ + if (handle_error && PNG_FAILED(result)) + png_error(png_ptr, "png_setting"); } - PNG_UNUSED(png_ptr) + else /* png_ptr is NULL */ + result = PNG_EINVAL; + + return result; + PNG_UNUSED(parameter) PNG_UNUSED(value) - return PNG_UNSUPPORTED_SETTING; } -#endif /* SETTING */ /* sRGB support */ #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ diff --git a/png.h b/png.h index 44b5f5cb4..b2c0072a0 100644 --- a/png.h +++ b/png.h @@ -832,11 +832,26 @@ typedef png_unknown_chunk * * png_unknown_chunkpp; #define PNG_COMPRESSION_TYPE_BASE 0 /* Deflate method 8, 32K window */ #define PNG_COMPRESSION_TYPE_DEFAULT PNG_COMPRESSION_TYPE_BASE -/* This is for filter type. PNG 1.0-1.2 only define the single type. */ +/* This is for filter method. PNG 1.0-1.2 only defines a single method. + * + * NOTE: CONFUSING NAME. The specification refers to a 'method', one of the + * defines below, and a 'type', one of the FILTER_VALUE defines. + * Historically libpng uses TYPE for 'method' and VALUE for 'type'. + */ #define PNG_FILTER_TYPE_BASE 0 /* Single row per-byte filtering */ #define PNG_INTRAPIXEL_DIFFERENCING 64 /* Used only in MNG datastreams */ #define PNG_FILTER_TYPE_DEFAULT PNG_FILTER_TYPE_BASE +/* Filter values defined for method '0' (PNG_FILTER_TYPE_BASE) in the PNG + * specification. + */ +#define PNG_FILTER_VALUE_NONE 0 +#define PNG_FILTER_VALUE_SUB 1 +#define PNG_FILTER_VALUE_UP 2 +#define PNG_FILTER_VALUE_AVG 3 +#define PNG_FILTER_VALUE_PAETH 4 +#define PNG_FILTER_VALUE_LAST 5 /* Not a valid value */ + /* These are for the interlacing type. These values should NOT be changed. */ #define PNG_INTERLACE_NONE 0 /* Non-interlaced image */ #define PNG_INTERLACE_ADAM7 1 /* Adam7 interlacing */ @@ -1122,11 +1137,25 @@ PNG_EXPORTA(5, png_structp, png_create_write_struct, * uInt is the type declared by zlib.h. On write setting the largest value will * typically cause the PNG image data to be written in one chunk; this gives the * smallest PNG and has little or no effect on applications that read the PNG. + * + * DEPRECATED: use png_set_IDAT_size on write and png_set_read_buffer_size on + * read. */ -PNG_EXPORT(6, png_alloc_size_t, png_get_compression_buffer_size, - (png_const_structrp png_ptr)); -PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structrp png_ptr, - png_alloc_size_t size)); +PNG_EXPORTA(6, png_alloc_size_t, png_get_compression_buffer_size, + (png_const_structrp png_ptr), PNG_DEPRECATED); +PNG_EXPORTA(7, void, png_set_compression_buffer_size, (png_structrp png_ptr, + png_alloc_size_t size), PNG_DEPRECATED); +#define png_set_read_buffer_size(p,size) (png_setting((p),\ + PNG_SR_COMPRESS_buffer_size, (size), 0)) + /* The size of the buffer used while processing compressed data, both single + * chunk data (zTXt, iTXt, iCCP) and IDAT data. With IDAT data in libpng 1.7 + * IDATs are read until the end or until the buffer is full; this means that + * you can optimize the buffer size for the particular memory behavior of + * your system and, possibly, your application. + * + * NOTE: the result (on success) is 0, which is actually an invalid value. + * Retrieving the current value is not possible. + */ /* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp * match up. @@ -1571,11 +1600,16 @@ PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structrp png_ptr, #endif #ifdef PNG_WRITE_FLUSH_SUPPORTED -/* Set how many lines between output flushes - 0 for no flushing */ -PNG_EXPORT(51, void, png_set_flush, (png_structrp png_ptr, int nrows)); +PNG_REMOVED(51, void, png_set_flush, (png_structrp png_ptr, int nrows), + PNG_EMPTY) +#define png_set_flush(p,v) (png_setting((p), PNG_SW_FLUSH, 0, (v))) + /* Set how many lines between output flushes - 0 for no flushing. The result + * on success is always 0. + */ + /* Flush the current PNG output buffer */ PNG_EXPORT(52, void, png_write_flush, (png_structrp png_ptr)); -#endif +#endif /* WRITE_FLUSH */ /* Optional update palette with requested transformations */ PNG_EXPORT(53, void, png_start_read_image, (png_structrp png_ptr)); @@ -1637,9 +1671,11 @@ PNG_EXPORT(64, void, png_destroy_read_struct, (png_structpp png_ptr_ptr, PNG_EXPORT(65, void, png_destroy_write_struct, (png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)); -/* Set the libpng method of handling chunk CRC errors */ -PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, - int ancil_action)); +/* Set the libpng method of handling chunk CRC errors on read */ +PNG_REMOVED(66, void, png_set_crc_action, (png_structrp png_ptr, + int crit_action, int ancil_action), PNG_EMPTY) +#define png_set_crc_action(png_ptr, crit, ancil)\ + (png_setting((png_ptr), PNG_SR_CRC_ACTION, (crit), (ancil))) /* Values for png_set_crc_action() say how to handle CRC errors in * ancillary and critical chunks, and whether to use the data contained @@ -1657,6 +1693,168 @@ PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, #define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ #define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ +/* Write image filtering and compression options. + * + * These settings just change the very low level encoding of a PNG. The changes + * make no difference to the image or the meta-data stored in the PNG. The API + * used to make these changes can be disabled in a very minimal configuration, + * if it is your compiler will report undefined values when the APIs below are + * used. + * + * Write settings defined here, in order of ease of use: + * + * 1) Write compression settings: whether to optimize the write and the PNG + * that results for read speed, final PNG size, write speed or memory + * usage. + * 2) IDAT size: What size to make the IDAT chunks in the PNG. + * 3) PNG row filters to consider when writing the PNG. + * 4) Very low level control over the deflate compression (useful mainly for + * programs that want to try every option to find which gives the smallest + * PNG.) + */ +#ifdef PNG_WRITE_SUPPORTED +/* (1) Write compression settings: */ +#define png_set_compression(p, v) (png_setting((p), PNG_SW_COMPRESS_png_level,\ + 0, (v))) + /* Control the write compression of all chunks. This affects five basic + * pieces of behavior: + * + * 1) The size of the PNG produced. + * 2) The amount of memory the write code takes to produce the PNG. + * 3) The amount of time the write code takes to produce the PNG. + * 4) The amount of memory required to read the resultant PNG. + * 5) The amount of time required to read the resultant PNG. + * + * There is considerable interdependence between these variables. As a + * result there are a limited number of options: + */ +# define PNG_COMPRESSION_LOW_MEMORY (1) + /* Minimize the memory required both when reading (4) and writing (2) the + * PNG. This results in a significantly larger PNG (which may itself have + * the opposite effect of slowing down either read or write) however the + * memory overhead is reduced and, apart from the extra time to read or + * write the data, the read and write time is likely to be reduced too. + * + * Use this when both read and write will happen on a memory starved + * (really, very low memory) system. + */ +# define PNG_COMPRESSION_HIGH_SPEED (2) + /* Minimize the time to both read (5) and write (3) the PNG. This uses + * slightly more memory on read and potentially significantly more on + * write but is optimized for maximum speed in both cases. + * + * Use this when both read and write need to be fast and PNG size is not + * likely to be an issue. An example would be if you are using PNG to + * pass intermediate data between applications on the same machine. + */ +# define PNG_COMPRESSION_HIGH_READ_SPEED (3) + /* Minimize the time to read (5) the PNG. This also reduces the amount + * of memory on read, however some options which require more memory but + * are likely to decrease PNG size, therefore improve read spead, are + * used. + * + * This is one of the 'normal' options; options that are used when a + * reasonably capable write machine is producing PNG files that will be + * read many times. In this case the option is optimizing for speed on + * read even if it increases the size of the PNG. + */ +# define PNG_COMPRESSION_LOW (4) + /* This switches on options which do affect speed of both compression and + * decompression, but biases the choice towards higher performance in both + * cases. (So it is something of a compromise between all-out speed and + * PNG compression). + * + * This is a good default to use in typical usages where PNG file size is + * less of an issue than the overheads on reading a PNG file. + * + * Use this option when producing PNG files that are not expected to be + * distributed widely or where read speed is more important that size. + * This is also a good default for small images where the slight increase + * in size of the compressed data doesn't change the file size much. + */ +# define PNG_COMPRESSION_MEDIUM (5) + /* This is a compromise which switches on the options found most helpful + * across a wide range of files without switching on the full range of + * options which would decrease file size only a little while taking a lot + * more time. PNG read memory (4) or time (5) is not a factor in the + * choice of options; only write time (3). + * + * This is closest to the default used in prior versions of libpng. There + * seems no logic to using it if the actual requirements are known and, + * even if they aren't, it is probably better to guess 'LOW' or 'HIGH'. + * + * This is the normal libpng default. + */ +# define PNG_COMPRESSION_HIGH (6) + /* This turns on everything which reduces file size on aggregate across a + * large test set of files. It optimizes solely for the size of the + * resultant PNG (1). + * + * This is a good default to use if file size is all important; it was the + * stated original default in the PNG design, but the implementation of + * libpng never used it. + * + * Use this setting in image authoring applications when writing the + * finished image in PNG format. + * + * NOTE: several PNG file size optimizers exist (see the web-site + * libpng.org). libpng does not perform the same functions as these + * optimizers; libpng does not search for the best compression settings. + * For this reason if you really want to minimize the size of the PNG files + * produced use PNG_COMPRESSION_HIGH_SPEED then post-process the result + * with one of the many PNG optimization programs. + */ +# define PNG_COMPRESSION_COMPAT (0) + /* DEPRECATED: this is provided as a setting to aid transition of test + * suites between major library versions (1.5 or 1.6 moving to 1.7). The + * default settings change in 1.7 so, while the PNG files produced do not + * change, their encoding does. Test systems that rely on constant + * encoding can use this to verify that this is all that has changed. + * + * NOTE: the option will be removed at some point. It is difficult to + * maintain and adds to libpng code size. + * + * NOTE: there are other changes in major and minor releases, such as + * better ancillary chunk error handling, that also cause binary changes + * to the PNG files libpng generates. Furthermore versions of libpng + * prior to 1.7 included random data from uninitialized memory in the + * image data under certain circumstances; this meant that earlier + * versions were often not even consistent across two writes of the same + * PNG file! + */ + +/* png_set_compression sets the default for all libpng compression operations. + * While the setting is the same for all chunks it results in different + * compression options for different chunks. The setting can be applied + * separately to each class of chunks as follows: + */ +#define png_set_image_compression(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_png_level, png_IDAT, (v))) + /* Control the compression of the image data (IDAT) chunks. */ + +#define png_set_ICC_profile_compression(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_png_level, png_iCCP, (v))) + /* Control the compression of ICC profiles (iCCP chunks.) */ + +#define png_set_text_compression(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_png_level, png_zTXt, (v))) + /* Control the compression of text (png_zTXt and png_iTXt) chunks. */ + +/* (2) IDAT size: */ +#define png_set_IDAT_size(p, v) (png_setting((p), PNG_SW_IDAT_size, (v), 0)) + /* Set the maximum size of the IDAT chunks libpng writes. Valid values are + * in the range 1U..0x7fffffffU, the default is 'PNG_ZBUF_SIZE' (a + * historically confusing name) and this default *also* controls the size of + * the buffer the read code uses when reading IDAT chunks. + * + * libpng has to buffer the data in the IDAT chunk before it writes any of + * it, therefore this number directly controls that part of the memory + * overhead while writing a PNG. There is a 12 byte per chunk overhead, so + * the number also directly affects the size of the PNG. The number has no + * significant effect (beyond the latter size effect) on the read code. + */ +#endif /* WRITE */ + /* These functions give the user control over the scan-line filtering in * libpng and the compression methods used by zlib. These functions are * mainly useful for testing, as the defaults should work with most users. @@ -1666,22 +1864,23 @@ PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, */ #ifdef PNG_WRITE_FILTER_SUPPORTED -/* Control the filtering method(s) used by libpng for the write of subsequent +/* (3) PNG row filters to consider when writing the PNG. + * + * Control the filtering method(s) used by libpng for the write of subsequent * rows of the image. The argument is either a single filter value (one of the - * PNG_FILTER_VALUE_ defines below), in which case that filter will be used on + * PNG_FILTER_VALUE_ defines above), in which case that filter will be used on * following rows, or a mask of filter values (logical or of the PNG_FILTER_ - * bit masks and follow PNG_FILTER_VALUE_*). + * bit masks that follow PNG_FILTER_VALUE_*). Support for selection of a filter + * from a mask with more than one bit set is dependent on + * PNG_SELECT_FILTER_SUPPORTED, however support is the default configuration of + * libpng. If support is not available the lowest bit set in the mask (the + * lowest numbered filter) is used. * * The set of filters may be changed at any time, the new values will affect the * next row written. * - * The first time a filter is selected which requires the previous row (UP, AVG - * or PAETH) retention of the previous row is switched on. This means that if - * this is done after the first row in a pass the previous-row filter will not - * be considered until the row after the png_set_filter call. libpng issues a - * warning (via png_warning) in this case. - * - * The 'method' must match that passed to png_set_IHDR; it cannot be changed. + * The 'method' must match that passed to png_set_IHDR; it cannot be changed and + * is ignore in 1.7 and later. * * If multiple filters are enabled libpng will select one according to the * following rules: @@ -1691,42 +1890,86 @@ PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, * when there is no previous row. * * 2) PNG_SELECT_FILTER_SUPPORTED: - * If the PNG rows are long enough (have enough bytes; at least 256) libpng - * will buffer each row and perform a filter selection heuristic to chose an - * appropriate filter. + * If the PNG rows are long enough (have enough bytes) libpng will process a + * row at a time; it will buffer the row if necessary. It uses a heuristic + * based on the closeness of the filtered values to 0 to determine which + * filter to use. * * 3) !PNG_SELECT_FILTER_SUPPORTED: * libpng selects the first filter in the list (there is no warning that this * will happen - check the #defines if you need to know.) * - * If you intend to use 'previous row' filters in an image set either the UP or - * PAETH filter before the first call to png_write_row, depending on whether you - * want to use NONE or SUB on the first row. + * The 'up', 'avg' and 'Paeth' filters require the previous image row to work. + * If it is not available they are removed from the set of filters to try. The + * first time the filter mask includes one of these filters libpng turns on + * saving of the row. The filters do work on the first row of a pass, where + * there is no previous row from the image. The PNG standard defines the + * previous row as consisting of all 0 bytes in this case. That definition + * causes the filters to have the following properties on the first row of a + * pass: * - * You can also select AVG on the first row; it uses half the value of the - * preceding byte as a predictor and is not likely to have very good - * performance. + * UP: The same as NONE (i.e. no filtering). + * AVG: Uses the arithmetic (not modular arithmetc!) half of the preceding + * pixel as the predictor. This is unique and not typically very + * useful. + * PAETH: The same as SUB. + * + * As a result with all versions of libpng if you want to use any of these + * filters anywhere in the image you need only turn on one of them on the first + * row of the image, or of a pass for interlaced images. For example if you + * want to use 'sub' on the first row simply set 'sub'+'Paeth' in the mask; + * libpng will automatically eliminate the Paeth algorithm from consideration + * because it knows that 'sub' will rank equal or (if the filter byte is taken + * into account) better. + * + * This approach is portable to earlier versions of libpng, however it may be + * difficult to program. 1.7 allows you to directly specify whether or not to + * retain the previous row. This is simpler and allows you to turn off previous + * row retention if you want to. */ -PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method, - int filters)); +PNG_REMOVED(67, void, png_set_filter, (png_structrp png_ptr, int method, + int filters), PNG_EMPTY) + +#define png_set_filter(p, m, f) (png_setting((p), PNG_SW_COMPRESS_filters,\ + (m), (f))) + /* 'm' is the method and must be 0 (PNG_FILTER_TYPE_BASE) unless MNG + * processing is supported (very unusual). 'f' is either a single value, + * PNG_FILTER_VALUE_* below, or a combination of one or more PNG_FILTER_MASK + * values. + * + * This sets the filter mask (or value) for the *next* row that is written. + * It may be called at any time but does not have any effect until the next + * row starts to be written. + * + * The return value is the mask that is set (or, with PNG_SF_GET, the + * currently set mask). When PNG_SELECT_FILTER_SUPPORTED is not defined this + * mask will have only one bit. + * + * NOTE: with PNG_SF_GET the result will be PNG_UNSET if png_set_filter has + * not been called before and row writing has not started. + */ + +#define png_set_row_buffers(p, onoff) (png_setting((p),\ + PNG_SW_COMPRESS_row_buffers, (onoff), 0)) + /* If you intend to change the filter list after the first row using the + * previous API call png_set_row_buffers(png_ptr, 1) if you intend to use UP, + * AVG or Paeth filters. + * + * You can turn the buffering on and off dynamically, just as with + * png_set_filter. + * + * The second argument should be 0 (off) or 1 (on). In the future it may be + * used to control the maximum number of rows buffered. + */ #endif /* WRITE_FILTER */ -/* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. - * These defines match the values in the PNG specification. - */ -#define PNG_FILTER_VALUE_NONE 0 -#define PNG_FILTER_VALUE_SUB 1 -#define PNG_FILTER_VALUE_UP 2 -#define PNG_FILTER_VALUE_AVG 3 -#define PNG_FILTER_VALUE_PAETH 4 -#define PNG_FILTER_VALUE_LAST 5 - -/* The above values are valid arguments to png_set_filter() if only a single - * filter is to be used. If multiple filters are to be allowed (the default is - * to allow any of them) then a combination of the following masks must be used - * and the low three bits of the argument to png_set_filter must be 0. +/* The PNG_FILTER_VALUE_ definitions (the filter values from the base PNG spec) + * are valid arguments to png_set_filter() if only a single filter is to be + * used. If multiple filters are to be allowed (the default is to allow any of + * them) then a combination of the following masks must be used and the low + * three bits of the argument to png_set_filter must be 0. * - * The resultant argument fits in a single byte. + * The resultant argument fits in a single byte in either case. */ #define PNG_FILTER_MASK(value) (0x08 << (value)) #define PNG_FILTER_NONE PNG_FILTER_MASK(PNG_FILTER_VALUE_NONE) @@ -1744,61 +1987,95 @@ PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method, #ifdef PNG_WRITE_SUPPORTED #ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */ -PNG_FP_EXPORT(68, PNG_DEPRECATED void, png_set_filter_heuristics, +PNG_REMOVED(68, void, png_set_filter_heuristics, (png_structrp png_ptr, int heuristic_method, int num_weights, - png_const_doublep filter_weights, png_const_doublep filter_costs)) -PNG_FIXED_EXPORT(209, PNG_DEPRECATED void, png_set_filter_heuristics_fixed, + png_const_doublep filter_weights, png_const_doublep filter_costs), + PNG_DEPRECATED) +PNG_REMOVED(209, void, png_set_filter_heuristics_fixed, (png_structrp png_ptr, int heuristic_method, int num_weights, png_const_fixed_point_p filter_weights, - png_const_fixed_point_p filter_costs)) + png_const_fixed_point_p filter_costs), + PNG_DEPRECATED) + /* Neither of these API calls did anything in libpng 1.6, however they were + * not marked PNG_DEPRECATED, so they are converted to no-op function-like + * macros here. (NOTE: the macro arguments are evaluated once each, this + * will probably cause warnings with some compiler options: simply remove the + * function call after ensuring that the arguments had no side effects.) + */ +#define png_set_filter_heuristics(p,m,w,fw,fc) ((void)(p,m,w,fw,fc)) +#define png_set_filter_heuristics_fixed(p,m,w,fw,fc) ((void)(p,m,w,fw,fc)) #endif /* WRITE_WEIGHTED_FILTER */ -/* 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 - * shown that zlib compression levels 3-6 usually perform as well as level 9 - * for PNG images, and do considerably fewer caclulations. In the future, - * these values may not correspond directly to the zlib compression levels. - */ #ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED -PNG_EXPORT(69, void, png_set_compression_level, (png_structrp png_ptr, - int level)); +PNG_REMOVED(69, void, png_set_compression_level, (png_structrp png_ptr, + int level), PNG_EMPTY) +#define png_set_compression_level(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_zlib_level, png_IDAT, (v))) -PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structrp png_ptr, - int mem_level)); +PNG_REMOVED(70, void, png_set_compression_mem_level, (png_structrp png_ptr, + int mem_level), PNG_EMPTY) +#define png_set_compression_mem_level(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_memLevel, png_IDAT, (v))) -PNG_EXPORT(71, void, png_set_compression_strategy, (png_structrp png_ptr, - int strategy)); +PNG_REMOVED(71, void, png_set_compression_strategy, (png_structrp png_ptr, + int strategy), PNG_EMPTY) +#define png_set_compression_strategy(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_strategy, png_IDAT, (v))) -/* 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_structrp png_ptr, - int window_bits)); +PNG_REMOVED(72, void, png_set_compression_window_bits, (png_structrp png_ptr, + int window_bits), PNG_EMPTY) +#define png_set_compression_window_bits(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_windowBits, png_IDAT, (v))) -PNG_EXPORT(73, void, png_set_compression_method, (png_structrp png_ptr, - int method)); +PNG_REMOVED(73, void, png_set_compression_method, (png_structrp png_ptr, + int method), PNG_EMPTY) +#define png_set_compression_method(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_method, png_IDAT, (v))) #endif /* WRITE_CUSTOMIZE_COMPRESSION */ #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_structrp png_ptr, - int level)); +PNG_REMOVED(222, void, png_set_text_compression_level, (png_structrp png_ptr, + int level), PNG_EMPTY) +#define png_set_text_compression_level(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_zlib_level, png_zTXt, (v))) -PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structrp png_ptr, - int mem_level)); +PNG_REMOVED(223, void, png_set_text_compression_mem_level, + (png_structrp png_ptr, int mem_level), PNG_EMPTY) +#define png_set_text_compression_mem_level(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_memLevel, png_zTXt, (v))) -PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structrp png_ptr, - int strategy)); +PNG_REMOVED(224, void, png_set_text_compression_strategy, (png_structrp png_ptr, + int strategy), PNG_EMPTY) +#define png_set_text_compression_strategy(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_strategy, png_zTXt, (v))) -/* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a - * smaller value of window_bits if it can do so safely. +PNG_REMOVED(225, void, png_set_text_compression_window_bits, + (png_structrp png_ptr, int window_bits), PNG_EMPTY) +#define png_set_text_compression_window_bits(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_windowBits, png_zTXt, (v))) + +PNG_REMOVED(226, void, png_set_text_compression_method, (png_structrp png_ptr, + int method), PNG_EMPTY) +#define png_set_text_compression_method(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_method, png_zTXt, (v))) + +/* NOTE: in versions of libpng prior to 1.7 iCCP compression was controlled by + * the text settings, hence the controls were only available if + * PNG_WRITE_CUSTOMIZIZE_ZTXT_COMPRESSION_SUPPORTED. In 1.7 the text settings + * no longer affect iCCP compression, the following macros must be used (if + * necessary): */ -PNG_EXPORT(225, void, png_set_text_compression_window_bits, - (png_structrp png_ptr, int window_bits)); - -PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr, - int method)); +#define png_set_ICC_profile_compression_level(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_zlib_level, png_iCCP, (v))) +#define png_set_ICC_profile_compression_mem_level(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_memLevel, png_iCCP, (v))) +#define png_set_ICC_profile_compression_strategy(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_strategy, png_iCCP, (v))) +#define png_set_ICC_profile_compression_window_bits(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_windowBits, png_iCCP, (v))) +#define png_set_ICC_profile_compression_method(p, v) (png_setting((p),\ + PNG_SW_COMPRESS_method, png_iCCP, (v))) #endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ #endif /* WRITE */ @@ -2077,8 +2354,31 @@ PNG_EXPORT(108, void, png_chunk_benign_error, (png_const_structrp png_ptr, png_const_charp warning_message)); #endif -PNG_EXPORT(109, void, png_set_benign_errors, - (png_structrp png_ptr, int allowed)); +#define png_set_error_action(png_ptr, what, action)\ + (png_setting((png_ptr), PNG_SRW_ERROR_HANDLING, (what), (action))) + /* Control the handling of 'benign' errors; errors that can be handled in + * some way. The action is one of the following values: + */ +#define PNG_IGNORE 0 /* ignore the error; no warning or error message */ +#define PNG_WARN 1 /* call png_warning with an appropriate error message */ +#define PNG_ERROR 2 /* call png_error with the error message */ + /* 'what' is a list (bit mask) of the errors to set: */ +#define PNG_BENIGN_ERRORS (1U) +#define PNG_APP_WARNINGS (2U) +#define PNG_APP_ERRORS (4U) +#define PNG_IDAT_ERRORS (8U) +#define PNG_SAFE_ERRORS (PNG_BENIGN_ERRORS+PNG_APP_WARNINGS+PNG_APP_ERRORS) +#define PNG_ALL_ERRORS (PNG_SAFE_ERRORS+PNG_IDAT_ERRORS) + +PNG_REMOVED(109, void, png_set_benign_errors, + (png_structrp png_ptr, int allowed), PNG_EMPTY) +#define png_set_benign_errors(png_ptr, allowed) (png_setting((png_ptr),\ + PNG_SRW_ERROR_HANDLING, PNG_SAFE_ERRORS,\ + (allowed) ? PNG_WARN : PNG_ERROR)) + /* Turn all errors that can be handled into warnings, or turn them back into + * errors if 'allowed' is false. + */ + #else # ifdef PNG_ALLOW_BENIGN_ERRORS # define png_benign_error(pp,e) png_warning(pp,e) @@ -2610,12 +2910,10 @@ PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structrp png_ptr, #define PNG_HANDLE_CHUNK_ALWAYS 3 #define PNG_HANDLE_CHUNK_LAST 4 -/* Strip the prepended error numbers ("#nnn ") from error and warning - * messages before passing them to the error or warning handler. - */ #ifdef PNG_ERROR_NUMBERS_SUPPORTED -PNG_EXPORT(185, void, png_set_strip_error_numbers, (png_structrp png_ptr, - png_uint_32 strip_mode)); +/* This was never implemented: */ +PNG_REMOVED(185, void, png_set_strip_error_numbers, (png_structrp png_ptr, + png_uint_32 strip_mode), PNG_EMPTY) #endif /* Added in libpng-1.2.6 */ @@ -2882,8 +3180,10 @@ PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i)); #endif #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED -PNG_EXPORT(242, void, png_set_check_for_invalid_index, - (png_structrp png_ptr, int enabled_if_greater_than_0)); +PNG_REMOVED(242, void, png_set_check_for_invalid_index, + (png_structrp png_ptr, int enabled_if_greater_than_0), PNG_EMPTY) +#define png_set_check_for_invalid_index(png_ptr, value)\ + (png_setting((png_ptr), PNG_SRW_CHECK_FOR_INVALID_INDEX, 0, (value))) /* By default the check is enabled on both read and write when the number of * entries in the palette is less than the maximum required by the bit depth * of a palette image. @@ -2895,6 +3195,8 @@ PNG_EXPORT(242, void, png_set_check_for_invalid_index, * On read chunk (benign) error messages are only produced with the default * setting; it is assumed that when the check is turned on explicitly the * caller will call png_get_palette_max to check the result. + * + * The png_setting call returns 0. */ #endif /* CHECK_FOR_INVALID_INDEX */ #ifdef PNG_GET_PALETTE_MAX_SUPPORTED @@ -3592,67 +3894,189 @@ PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory, * Section 6: IMPLEMENTATION OPTIONS ******************************************************************************* * - * Support for arbitrary implementation-specific optimizations. The API allows - * particular options to be turned on or off. 'Option' is the number of the - * option and 'onoff' is 0 (off) or non-0 (on). The value returned is given - * by the PNG_OPTION_ defines below. + * Change of options used during read and/or write. * - * HARDWARE: normally hardware capabilites, such as the Intel SSE instructions, - * are detected at run time, however sometimes it may be impossible - * to do this in user mode, in which case it is necessary to discover - * the capabilities in an OS specific way. Such capabilities are - * listed here when libpng has support for them and must be turned - * ON by the application if present. Check pnglibconf.h for options - * appropriate to your hardware. + * A number of internal options can (but do not need to be) changed to + * fine tune the implementation. These options control such things as the + * precise settings for compression, the accuracy of arithmetic used internally + * for image processing operations (gamma transformations) and, in some cases, + * the specific implementations (hardware or software optimizations.) * - * In general 'PNG_EXTENSIONS' controls hardware optimizations; these - * are not supported parts of libpng and, if there are problems with - * them, bugs should be ported to the implementers. Depending on the - * configuration it may not be possible to disable extensions at run - * time. - * - * SOFTWARE: sometimes software optimizations actually result in performance - * decrease on some architectures or systems, or with some sets of - * PNG images. 'Software' options allow such optimizations to be - * selected at run time. + * To avoid API proliferation there is a single general API (new in 1.7) to do + * this. When a particular option is not supported by the build in libpng an + * attempt to set it will return a failure code but will be totally ignored + * unless the PNG_SF_ERROR flag is set (see below). */ -#ifdef PNG_SET_OPTION_SUPPORTED -#define PNG_EXTENSIONS 0 /* BOTH: enable or disable extensions */ -#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */ -#define PNG_SKIP_sRGB_CHECK_PROFILE 4 /* SOFTWARE: Check ICC profile for sRGB */ -#define PNG_OPTION_NEXT 6 /* Next option - numbers must be even */ +PNG_EXPORT(249, png_int_32, png_setting, (png_structrp png_ptr, + png_uint_32 setting, png_uint_32 parameter, png_int_32 value)); + /* Alter setting 'setting' using the values of 'parameter' and 'value'. The + * result is either one of the following failure codes or a setting/parameter + * specific result code. + * + * The failure codes match the POSIX 1003.1 values (section 2.5, + * error numbers) with a preceding PNG_. (png_uint_32)result gives a number + * in the range 0x80000001U to 0x8000000fU. + */ +# define PNG_EBADF (-0x7fffffff) /* read/write error */ + /* An attempt was made to apply a read setting to a write structure or + * vice versa. + */ +# define PNG_EINVAL (-0x7ffffffe) /* invalid argument */ + /* 'png_ptr' was NULL or 'parameter' or 'value' is invalid for the given + * setting. + */ +# define PNG_EDOM (-0x7ffffffd) /* out of range */ + /* Either 'parameter' or 'value' is out of range for the given setting + * (only returned when paramter or value are used and are numeric; for + * flag values PNG_EINVAL will be returned.) + */ +# define PNG_ENOSYS (-0x7ffffff1) /* unsupported setting/param */ + /* The setting was not recognized; typically this means that libpng was + * built without the appropriate support. + */ +# define PNG_UNSUPPORTED_SETTING PNG_ENOSYS + /* For backware compatibility with earlier libpng versions and + * 'png_set_option' return codes. + */ +# define PNG_UNSET (-0x7ffffff0) /* NOT an erro code: no previous setting */ + /* The setting was not (previously) set. Returned when there is no built + * in default for a setting. Normally this means that the default will + * depend on other settings or the PNG itself. + */ + /* Results larger (more positive) than PNG_ENOSYS are success codes (even if + * negative). The value is interpreted as follows (as defined by the + * setting): + * + * 1) A signed 31-bit number in the range -0x7fffffef to +0x7fffffff + * 2) An unsigned 31 bit number in the range 0U to 0x7fffffffU + * 3) An unsigned 32 bit bit set/flag value in the range 0U to 0xfffffffU + * but excluding values in the range 0x80000000U to 0x80000000FU + * encoded as follows: + * + * if (v <= 0x7fffffffU) + * v + * else if (v > 0x8000000FU) + * -(png_int_32)-v + * + * The result can be converted by to the original (png_uint_32) simply + * by casting it as such. + */ +# define PNG_FAILED(result) ((result) <= PNG_ENOSYS) + /* The setting did not take; this includes both errors making the setting + * (e.g. parameter or value errors) and unsupported settings. Check the + * result code itself for more information. + */ +# define PNG_OK(result) ((result) > PNG_ENOSYS) + /* The setting succeeded; the result is a return code which depends on the + * particular setting. (E.g. it might be a return code or it might be the + * previous value.) + */ -/* Return values: NOTE: there are four values and 'off' is *not* zero */ -#define PNG_OPTION_UNSET 0 /* Unset - defaults to off */ -#define PNG_OPTION_INVALID 1 /* Option number out of range */ -#define PNG_OPTION_OFF 2 -#define PNG_OPTION_ON 3 - -PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option, - int onoff)); -#endif /* SET_OPTION */ - -/* Support for software run-time settings. +/* SETTING VALUES (generic) * - * These settings allow tuning of the parameters used internally by libpng to - * achieve either greater performance, lower memory utilization or greater - * accuracy in image processing operations. - * - * The parameter is a single png_int_32, the result is the previous setting or - * 0x8000000 if the setting is not supported.. + * These are flag values that are added to the setting definitions below to + * simplify processing inside libpng and self-document the setting behavior. + * All these values have the prefix PNG_SF_ */ -#ifdef PNG_SETTING_SUPPORTED -PNG_EXPORT(249, png_int_32, png_setting, (png_structrp png_ptr, int setting, - png_int_32 value)); +#define PNG_SF_ERROR (0x80000000U) + /* If this is set on the 'setting' argument to png_setting and a failure code + * would otherwise be returned call png_error instead. This is a convenience + * for applications that do not want to check the result code. It is never + * set by default. The error string is cryptic. + */ +#define PNG_SF_GET (0x40000000U) + /* Do not set the setting. With most settings this just allows for the + * presence of support for the setting to be checked at run time; if the + * setting is not support PNG_ENOSYS will be returned. + * + * With some settings checking of the parameter or value may be done, but + * there is no guarantee, so always supply valid parameter and value. + * + * With some settings the current setting is returned. This is typically + * only done when the default setting is configurable and not even always + * then. If the setting does this it will document the behavior. + */ +#define PNG_SF_READ (0x20000000U) + /* The setting may be applied to a read png_struct. If this is not set and + * an attempt is made to apply the setting to a read struct + * PNG_EBADF will be returned. + */ +#define PNG_SF_WRITE (0x10000000U) + /* The setting may be applied to a write png_struct. If this is not set + * and an attempt is made to apply the setting to a write struct + * PNG_EBADF will be returned. + */ -#define PNG_UNSUPPORTED_SETTING 0x80000000U +/*********************************** WRITE ************************************/ +/* WRITE COMPRESSION SUPPORT + * + * These settings are normally accessed using the macros that are defined above; + * the function-like macros replace the API calls present in previous versions + * of libpng. + * + * 'setting' is as follows, 'parameter' is a chunk name; png_IDAT for IDAT + * compression, png_iCCP for iCCP chunk compression png_zTXt for zTZt *and* iTXt + * text chunk compression. Other values must not be used; they will result in + * PNG_ENOSYS at present but may alter compression of new chunks in the future. + * + * The value is the new compression setting. The result is is the old + * compression setting or an error code. Compression settings are documented + * in text above describing the function-like macros. PNG_UNSET is returned + * when the setting was not previously set; in this case the default may vary + * according to the actual data (e.g. length, PNG format). + * + * 0 is valid as a parameter if PNG_SF_GET is set, in that case the current or + * last setting is returned. + */ +#define PNG_SW_COMPRESS_zlib_level (PNG_SF_WRITE + 0U) +#define PNG_SW_COMPRESS_windowBits (PNG_SF_WRITE + 1U) +#define PNG_SW_COMPRESS_memLevel (PNG_SF_WRITE + 2U) +#define PNG_SW_COMPRESS_strategy (PNG_SF_WRITE + 3U) +#define PNG_SW_COMPRESS_png_level (PNG_SF_WRITE + 4U) +#define PNG_SW_COMPRESS_method (PNG_SF_WRITE + 5U) -/* Available settings: */ -#define PNG_GAMMA_MINIMUM 1 +/* WRITE IDAT size. + * + * The size of the IDAT chunks that are written (the last may be smaller). + */ +#define PNG_SW_IDAT_size (PNG_SF_WRITE + 6U) + +/* WRITE FILTER CONTROL + * + * These settings are used by png_set_filter and png_set_row_buffers to control + * the filters used during compression. The 'filters' setting has two arguments + * however the first is the filter method (or type) and must be 0 for PNG. + * Standards based on PNG may define additional values, as with other base file + * characteristics such as the compression type, however the result would not be + * a PNG. + */ +#define PNG_SW_COMPRESS_filters (PNG_SF_WRITE + 7U) +#define PNG_SW_COMPRESS_row_buffers (PNG_SF_WRITE + 8U) + +/* WRITE ROW FLUSH CONTROL + * + * This sets the number of rows between flush calls. '0' was used to indicate + * no flushing (before the end). The maximum number of rows in a PNG is + * actually greater than the maximum of a 31-bit integer for interlaced images, + * however this doesn't matter much; the number of rows was always declared as + * 'int', so it is still passed in the 'value' argument. + */ +#define PNG_SW_FLUSH (PNG_SF_WRITE + 9U) + +/*********************************** READ *************************************/ +/* The size of the buffer used while reading IDAT chunks and, potentially, other + * compressed chunks. + */ +#define PNG_SR_COMPRESS_buffer_size (PNG_SF_READ + 1U) + /* Read compressed data buffer size, in 'parameter'. The result is 0. */ + +#define PNG_SR_GAMMA_threshold (PNG_SF_READ + 2U) +#define png_set_gamma_threshold(png_ptr, threshold)\ + (png_setting((png_ptr), PNG_SR_GAMMA_threshold, (threshold), 0)) /* SETTING: threshold below which gamma correction is not done, the default * (set when the library is built) is PNG_GAMMA_THRESHOLD_FIXED, the - * parameter is a png_fixed_point number, the difference from PNG_FP_1 above - * which gamma correction will be performed. + * 'parameter' is a png_fixed_point number, the difference from PNG_FP_1 + * above which gamma correction will be performed. * * The value '153' is sufficient to maintain 1% accuracy in 16-bit linear * calculations over a 655:1 range; over the maximum range possible with the @@ -3684,10 +4108,13 @@ PNG_EXPORT(249, png_int_32, png_setting, (png_structrp png_ptr, int setting, * Values between 216 and 5000 produce varying very small changes in image * contrast. Values above 10,000 (10%) produce noticeable increase or * decrease in contrast which will probably change how the image is - * perceived. + * perceived. There is an internal limit on the maximum value which is + * currently 65%; PNG_EDOM will be returned for higher values. + * + * The result is the value that was set. */ #if 0 /*NYI*/ -#define PNG_GAMMA_ACCURACY 2 +#define PNG_SR_GAMMA_accuracy /*NYI*/ /* SETTING: controls the accuracy of the gamma calculations when the results * are cached. The default is PNG_DEFAULT_GAMMA_ACCURACY. The number is 100 * times the number of bits, 'b', used in the internal tables when the input @@ -3714,7 +4141,62 @@ PNG_EXPORT(249, png_int_32, png_setting, (png_structrp png_ptr, int setting, * 16 5 1.0 5 384 */ #endif /*NYI*/ -#endif /* SETTING */ + +#define PNG_SR_CRC_ACTION (PNG_SF_READ + 4U) + /* 'parameter' is what to do with critical chunks, 'value' is what to do with + * ancillary ones when the CRC does not match on read. 0 is returned. See + * png_set_crc_action for more information. + */ + +/*********************************** OPTIONS **********************************/ +/* png_set_option is implemented via png_setting to provide API compatibility + * with releases prior to 1.7.0 + */ +/* HARDWARE OPTIMIZATIONS + * + * Normally hardware capabilites, such as the Intel SSE instructions, are + * detected at run time, however sometimes it may be impossible to do this in + * user mode, in which case it is necessary to discover the capabilities in an + * OS specific way. Such capabilities are listed here when libpng has support + * for them and must be turned ON by the application if present. Check + * pnglibconf.h for options appropriate to your hardware. + * + * In general 'PNG_EXTENSIONS' controls hardware optimizations; these are not + * supported parts of libpng and, if there are problems with them, bugs should + * be ported to the implementers. Depending on the configuration it may not be + * possible to disable extensions at run time. + */ +#define PNG_SRW_OPTION (PNG_SF_READ+PNG_SF_WRITE + 0U) +#ifdef PNG_SET_OPTION_SUPPORTED +PNG_REMOVED(244, int, png_set_option, (png_structrp png_ptr, int option, + int onoff), PNG_EMPTY) + +#define png_set_option(p, opt, onoff)\ + (png_setting((p), PNG_SRW_OPTION, (opt), (onoff))) + /* Pre 1.7 API; in 1.7 the result values have changed numerically but not by + * name. For backward API compatibility this setting only returns one error + * code, PNG_ENOSYS and that only for option numbers out of range, otherwise + * if the option isn't supported PNG_OPTION_UNSET (PNG_UNSET) is returned. + */ +#endif /* SET_OPTION */ +#define PNG_OPTION_UNSET PNG_UNSET /* Unset - defaults to off */ +#define PNG_OPTION_INVALID PNG_ENOSYS /* Option number out of range */ +#define PNG_OPTION_OFF 0 +#define PNG_OPTION_ON 1 + +/* Specific options: */ +#define PNG_EXTENSIONS 0 /* HARDWARE: switch extensions on or off */ +#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */ +#define PNG_SKIP_sRGB_CHECK_PROFILE 4 /* SOFTWARE: Check ICC profile for sRGB */ +#define PNG_OPTION_NEXT 6 /* Next option - numbers are even */ + +#define PNG_SRW_CHECK_FOR_INVALID_INDEX (PNG_SF_READ+PNG_SF_WRITE + 1U) + /* Turn the palette index check on or off; see + * png_set_check_for_invalid_index above. + */ + +#define PNG_SRW_ERROR_HANDLING (PNG_SF_READ+PNG_SF_WRITE + 2U) + /* Change the action on issues that can be handled. */ /******************************************************************************* * END OF HARDWARE OPTIONS diff --git a/pngdebug.h b/pngdebug.h index c1368cb19..4bfff4de3 100644 --- a/pngdebug.h +++ b/pngdebug.h @@ -35,9 +35,6 @@ #define PNGDEBUG_H /* These settings control the formatting of messages in png.c and pngerror.c */ /* Moved to pngdebug.h at 1.5.0 */ -# ifndef PNG_LITERAL_SHARP -# define PNG_LITERAL_SHARP 0x23U -# endif # ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET # define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5bU # endif diff --git a/pngerror.c b/pngerror.c index 41bd4d038..453ff07b7 100644 --- a/pngerror.c +++ b/pngerror.c @@ -40,46 +40,6 @@ PNG_FUNCTION(void,PNGAPI png_error,(png_const_structrp png_ptr, png_const_charp error_message), PNG_NORETURN) { -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - char msg[16]; - if (png_ptr != NULL) - { - if ((png_ptr->flags & - (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0) - { - if (*error_message == PNG_LITERAL_SHARP) - { - /* Strip "#nnnn " from beginning of error message. */ - int offset; - for (offset = 1; offset<15; offset++) - if (error_message[offset] == ' ') - break; - - if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0) - { - int i; - for (i = 0; i < offset - 1; i++) - msg[i] = error_message[i + 1]; - msg[i - 1] = '\0'; - error_message = msg; - } - - else - error_message += offset; - } - - else - { - if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0) - { - msg[0] = '0'; - msg[1] = '\0'; - error_message = msg; - } - } - } - } -#endif if (png_ptr != NULL && png_ptr->error_fn != NULL) (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), error_message); @@ -218,21 +178,6 @@ void PNGAPI png_warning(png_const_structrp png_ptr, png_const_charp warning_message) { int offset = 0; - if (png_ptr != NULL) - { -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - if ((png_ptr->flags & - (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0) -#endif - { - if (*warning_message == PNG_LITERAL_SHARP) - { - for (offset = 1; offset < 15; offset++) - if (warning_message[offset] == ' ') - break; - } - } - } if (png_ptr != NULL && png_ptr->warning_fn != NULL) (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr), warning_message + offset); @@ -363,24 +308,41 @@ png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p, void PNGAPI png_benign_error(png_const_structrp png_ptr, png_const_charp error_message) { - if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0) + switch (png_ptr->benign_error_action) { -# ifdef PNG_READ_SUPPORTED - if (png_ptr->read_struct && png_ptr->chunk_name != 0) - png_chunk_warning(png_ptr, error_message); - else -# endif - png_warning(png_ptr, error_message); + case PNG_ERROR: + png_chunk_error(png_ptr, error_message); + break; + + case PNG_WARN: + png_chunk_warning(png_ptr, error_message); + break; + + default: /* PNG_IGNORE */ + break; } - else +# ifndef PNG_ERROR_TEXT_SUPPORTED + PNG_UNUSED(error_message) +# endif +} + +static void +app_error(png_const_structrp png_ptr, png_const_charp error_message, + unsigned int error_action) +{ + switch (error_action) { -# ifdef PNG_READ_SUPPORTED - if (png_ptr->read_struct && png_ptr->chunk_name != 0) - png_chunk_error(png_ptr, error_message); - else -# endif - png_error(png_ptr, error_message); + case PNG_ERROR: + png_error(png_ptr, error_message); + break; + + case PNG_WARN: + png_warning(png_ptr, error_message); + break; + + default: /* PNG_IGNORE */ + break; } # ifndef PNG_ERROR_TEXT_SUPPORTED @@ -391,27 +353,13 @@ png_benign_error(png_const_structrp png_ptr, png_const_charp error_message) void /* PRIVATE */ png_app_warning(png_const_structrp png_ptr, png_const_charp error_message) { - if ((png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) != 0) - png_warning(png_ptr, error_message); - else - png_error(png_ptr, error_message); - -# ifndef PNG_ERROR_TEXT_SUPPORTED - PNG_UNUSED(error_message) -# endif + app_error(png_ptr, error_message, png_ptr->app_error_action); } void /* PRIVATE */ png_app_error(png_const_structrp png_ptr, png_const_charp error_message) { - if ((png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) != 0) - png_warning(png_ptr, error_message); - else - png_error(png_ptr, error_message); - -# ifndef PNG_ERROR_TEXT_SUPPORTED - PNG_UNUSED(error_message) -# endif + app_error(png_ptr, error_message, png_ptr->app_warning_action); } #endif /* BENIGN_ERRORS */ @@ -488,7 +436,7 @@ png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message), PNG_NORETURN) { char msg[18+PNG_MAX_ERROR_TEXT]; - if (png_ptr == NULL) + if (png_ptr == NULL || png_ptr->chunk_name == 0U) png_error(png_ptr, error_message); else @@ -504,7 +452,7 @@ void PNGAPI png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message) { char msg[18+PNG_MAX_ERROR_TEXT]; - if (png_ptr == NULL) + if (png_ptr == NULL || png_ptr->chunk_name == 0U) png_warning(png_ptr, warning_message); else @@ -521,17 +469,25 @@ void PNGAPI png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp error_message) { - if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0) - png_chunk_warning(png_ptr, error_message); + switch (png_ptr->benign_error_action) + { + case PNG_ERROR: + png_chunk_error(png_ptr, error_message); + break; - else - png_chunk_error(png_ptr, error_message); + case PNG_WARN: + png_chunk_warning(png_ptr, error_message); + break; + + default: /* PNG_IGNORE */ + break; + } # ifndef PNG_ERROR_TEXT_SUPPORTED PNG_UNUSED(error_message) # endif } -#endif +#endif /* BENIGN_ERRORS */ #endif /* READ */ void /* PRIVATE */ @@ -732,37 +688,6 @@ png_default_error,(png_const_structrp png_ptr, png_const_charp error_message), PNG_NORETURN) { #ifdef PNG_CONSOLE_IO_SUPPORTED -#ifdef PNG_ERROR_NUMBERS_SUPPORTED - /* 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; - char error_number[16]; - for (offset = 0; offset<15; offset++) - { - error_number[offset] = error_message[offset + 1]; - if (error_message[offset] == ' ') - break; - } - - if ((offset > 1) && (offset < 15)) - { - error_number[offset - 1] = '\0'; - fprintf(stderr, "libpng error no. %s: %s", - error_number, error_message + offset + 1); - fprintf(stderr, PNG_STRING_NEWLINE); - } - - else - { - fprintf(stderr, "libpng error: %s, offset=%d", - error_message, offset); - fprintf(stderr, PNG_STRING_NEWLINE); - } - } - else -#endif { fprintf(stderr, "libpng error: %s", error_message ? error_message : "undefined"); @@ -809,36 +734,6 @@ static void /* PRIVATE */ png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message) { #ifdef PNG_CONSOLE_IO_SUPPORTED -# ifdef PNG_ERROR_NUMBERS_SUPPORTED - if (*warning_message == PNG_LITERAL_SHARP) - { - int offset; - char warning_number[16]; - for (offset = 0; offset < 15; offset++) - { - warning_number[offset] = warning_message[offset + 1]; - if (warning_message[offset] == ' ') - break; - } - - if ((offset > 1) && (offset < 15)) - { - warning_number[offset + 1] = '\0'; - fprintf(stderr, "libpng warning no. %s: %s", - warning_number, warning_message + offset); - fprintf(stderr, PNG_STRING_NEWLINE); - } - - else - { - fprintf(stderr, "libpng warning: %s", - warning_message); - fprintf(stderr, PNG_STRING_NEWLINE); - } - } - else -# endif - { fprintf(stderr, "libpng warning: %s", warning_message); fprintf(stderr, PNG_STRING_NEWLINE); @@ -886,19 +781,6 @@ png_get_error_ptr(png_const_structrp png_ptr) } -#ifdef PNG_ERROR_NUMBERS_SUPPORTED -void PNGAPI -png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode) -{ - if (png_ptr != NULL) - { - png_ptr->flags &= - ((PNG_BIC_MASK(PNG_FLAG_STRIP_ERROR_NUMBERS | - PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode); - } -} -#endif - #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) /* Currently the above both depend on SETJMP_SUPPORTED, however it would be diff --git a/pngpread.c b/pngpread.c index c7dc3178f..fb07de75d 100644 --- a/pngpread.c +++ b/pngpread.c @@ -26,7 +26,9 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) return; ptr = buffer; - if (png_ptr->save_buffer_size != 0) + debug(length > 0); + + if (length > 0 && png_ptr->save_buffer_size > 0) { png_size_t save_size; @@ -44,7 +46,7 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) png_ptr->save_buffer_ptr += save_size; } - if (length != 0 && png_ptr->current_buffer_size != 0) + if (length > 0 && png_ptr->current_buffer_size > 0) { png_size_t save_size; @@ -734,15 +736,13 @@ png_push_read_chunk_header(png_structrp png_ptr, png_infop info_ptr) * of the data. */ unsigned int mode; /* mode prior to the header */ - png_byte chunk_length[4]; - png_byte chunk_tag[4]; + png_byte chunk_header[8]; PNG_PUSH_SAVE_BUFFER_IF_LT(8) - png_push_fill_buffer(png_ptr, chunk_length, 4); - png_ptr->chunk_length = png_get_uint_31(png_ptr, chunk_length); - png_reset_crc(png_ptr); - png_crc_read(png_ptr, chunk_tag, 4); - png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag); + png_push_fill_buffer(png_ptr, chunk_header, 8); + png_ptr->chunk_length = png_get_uint_31(png_ptr, chunk_header); + png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_header+4); + png_reset_crc(png_ptr, chunk_header+4); mode = png_ptr->mode; png_ptr->process_mode = png_check_bits(png_ptr, png_read_chunk+png_find_chunk_op(png_ptr), 4); diff --git a/pngpriv.h b/pngpriv.h index f09e5dd8b..247e43c36 100644 --- a/pngpriv.h +++ b/pngpriv.h @@ -623,22 +623,16 @@ */ #define PNG_FLAG_LIBRARY_MISMATCH 0x001U /*#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x002U NO LONGER USED */ -#define PNG_FLAG_CRC_ANCILLARY_USE 0x004U -#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x008U -#define PNG_FLAG_CRC_CRITICAL_USE 0x010U -#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x020U -#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x040U -#define PNG_FLAG_STRIP_ERROR_TEXT 0x080U -#define PNG_FLAG_IDAT_ERRORS_WARN 0x100U -#define PNG_FLAG_BENIGN_ERRORS_WARN 0x200U -#define PNG_FLAG_APP_WARNINGS_WARN 0x400U -#define PNG_FLAG_APP_ERRORS_WARN 0x800U - -#define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ - PNG_FLAG_CRC_ANCILLARY_NOWARN) - -#define PNG_FLAG_CRC_CRITICAL_MASK (PNG_FLAG_CRC_CRITICAL_USE | \ - PNG_FLAG_CRC_CRITICAL_IGNORE) +/*#define PNG_FLAG_CRC_ANCILLARY_USE 0x004U NO LONGER USED */ +/*#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x008U NO LONGER USED */ +/*#define PNG_FLAG_CRC_CRITICAL_USE 0x010U NO LONGER USED */ +/*#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x020U NO LONGER USED */ +/*#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x040U NEVER USED */ +/*#define PNG_FLAG_STRIP_ERROR_TEXT 0x080U NEVER USED */ +/*#define PNG_FLAG_IDAT_ERRORS_WARN 0x100U NEVER SET */ +/*#define PNG_FLAG_BENIGN_ERRORS_WARN 0x200U NO LONGER USED */ +/*#define PNG_FLAG_APP_WARNINGS_WARN 0x400U NO LONGER USED */ +/*#define PNG_FLAG_APP_ERRORS_WARN 0x800U NO LONGER USED */ #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) @@ -1050,8 +1044,12 @@ PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_flush,(png_structp png_ptr), # endif /* WRITE */ #endif /* STDIO */ -/* Reset the CRC variable */ -PNG_INTERNAL_FUNCTION(void,png_reset_crc,(png_structrp png_ptr),PNG_EMPTY); +/* Reset the CRC variable. The CRC is initialized with the chunk tag (4 bytes). + * NOTE: at present png_struct::chunk_name MUST be set before this as well so + * that png_struct::current_crc is initialized correctly! + */ +PNG_INTERNAL_FUNCTION(void,png_reset_crc,(png_structrp png_ptr, + png_const_bytep chunk_tag), PNG_EMPTY); /* Write the "data" buffer to whatever output you are using */ PNG_INTERNAL_FUNCTION(void,png_write_data,(png_structrp png_ptr, @@ -2230,6 +2228,20 @@ PNG_INTERNAL_FUNCTION(void, png_image_free, (png_imagep image), PNG_EMPTY); #endif /* SIMPLIFIED READ/WRITE */ +#ifdef PNG_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(png_int_32, png_read_setting, (png_structrp png_ptr, + png_uint_32 setting, png_uint_32 parameter, png_int_32 value), PNG_EMPTY); +#endif /* READ */ +#ifdef PNG_WRITE_SUPPORTED +PNG_INTERNAL_FUNCTION(png_int_32, png_write_setting, (png_structrp png_ptr, + png_uint_32 setting, png_uint_32 parameter, png_int_32 value), PNG_EMPTY); + /* Implementations of read and write settings, in pngrutil.c and pngwutil.c + * respectively. + */ +#endif /* WRITE */ + +/* Maintainer: Put new private prototypes here ^ */ + /* These are initialization functions for hardware specific PNG filter * optimizations; list these here then select the appropriate one at compile * time using the macro PNG_FILTER_OPTIMIZATIONS. If the macro is not defined @@ -2248,8 +2260,6 @@ PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon, (png_structp png_ptr, unsigned int bpp), PNG_EMPTY); #endif -/* Maintainer: Put new private prototypes here ^ */ - #include "pngdebug.h" /* EXTENSION SPECIFIC FUNCTIONS */ diff --git a/pngread.c b/pngread.c index e89ffb986..b5fc7aad1 100644 --- a/pngread.c +++ b/pngread.c @@ -21,75 +21,6 @@ #define PNG_SRC_FILE PNG_SRC_FILE_pngread #ifdef PNG_READ_SUPPORTED - -/* Set the action on getting a CRC error for an ancillary or critical chunk. */ -void PNGAPI -png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action) -{ - png_debug(1, "in png_set_crc_action"); - - if (png_ptr == NULL) - return; - - /* Tell libpng how we react to CRC errors in critical chunks */ - switch (crit_action) - { - case PNG_CRC_NO_CHANGE: /* Leave setting as is */ - break; - - case PNG_CRC_WARN_USE: /* Warn/use data */ - png_ptr->flags &= PNG_BIC_MASK(PNG_FLAG_CRC_CRITICAL_MASK); - png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE; - break; - - case PNG_CRC_QUIET_USE: /* Quiet/use data */ - png_ptr->flags &= PNG_BIC_MASK(PNG_FLAG_CRC_CRITICAL_MASK); - png_ptr->flags |= PNG_FLAG_CRC_CRITICAL_USE | - PNG_FLAG_CRC_CRITICAL_IGNORE; - break; - - case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */ - png_warning(png_ptr, - "Can't discard critical data on CRC error"); - case PNG_CRC_ERROR_QUIT: /* Error/quit */ - - case PNG_CRC_DEFAULT: - default: - png_ptr->flags &= PNG_BIC_MASK(PNG_FLAG_CRC_CRITICAL_MASK); - break; - } - - /* Tell libpng how we react to CRC errors in ancillary chunks */ - switch (ancil_action) - { - case PNG_CRC_NO_CHANGE: /* Leave setting as is */ - break; - - case PNG_CRC_WARN_USE: /* Warn/use data */ - png_ptr->flags &= PNG_BIC_MASK(PNG_FLAG_CRC_ANCILLARY_MASK); - png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE; - break; - - case PNG_CRC_QUIET_USE: /* Quiet/use data */ - png_ptr->flags &= PNG_BIC_MASK(PNG_FLAG_CRC_ANCILLARY_MASK); - png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_USE | - PNG_FLAG_CRC_ANCILLARY_NOWARN; - break; - - case PNG_CRC_ERROR_QUIT: /* Error/quit */ - png_ptr->flags &= PNG_BIC_MASK(PNG_FLAG_CRC_ANCILLARY_MASK); - png_ptr->flags |= PNG_FLAG_CRC_ANCILLARY_NOWARN; - break; - - case PNG_CRC_WARN_DISCARD: /* Warn/discard data */ - - case PNG_CRC_DEFAULT: - default: - png_ptr->flags &= PNG_BIC_MASK(PNG_FLAG_CRC_ANCILLARY_MASK); - break; - } -} - /* Create a PNG structure for reading, and allocate any memory needed. */ PNG_FUNCTION(png_structp,PNGAPI png_create_read_struct,(png_const_charp user_png_ver, png_voidp error_ptr, @@ -118,30 +49,42 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, if (png_ptr != NULL) { png_ptr->read_struct = 1; + png_ptr->critical_crc = crc_error_quit; + png_ptr->ancillary_crc = crc_warn_discard; + +# ifdef PNG_BENIGN_ERRORS_SUPPORTED +# if !PNG_RELEASE_BUILD + /* Always quit on error prior to release */ + png_ptr->benign_error_action = PNG_ERROR; + png_ptr->app_warning_action = PNG_ERROR; + png_ptr->app_error_action = PNG_ERROR; +# else /* RELEASE_BUILD */ + /* Allow benign errors on read, subject to app control. */ + png_ptr->benign_error_action = PNG_WARN; +# ifdef PNG_BENIGN_READ_ERRORS_SUPPORTED + png_ptr->app_error_action = PNG_WARN; + png_ptr->app_warning_action = PNG_WARN; +# else /* !BENIGN_READ_ERRORS */ + /* libpng build without benign error support; the application + * author has to be assumed to be correct, so: + */ + png_ptr->app_warning_action = PNG_ERROR; + png_ptr->app_error_action = PNG_ERROR; +# endif /* !BENIGN_READ_ERRORS */ +# endif /* RELEASE_BUILD */ + + /* This is always png_error unless explicitly changed: */ + png_ptr->IDAT_error_action = PNG_ERROR; +# endif /* BENIGN_ERRORS */ - /* Added in libpng-1.6.0; this can be used to detect a read structure if - * required (it will be zero in a write structure.) - */ # ifdef PNG_SEQUENTIAL_READ_SUPPORTED png_ptr->IDAT_size = PNG_IDAT_READ_SIZE; # endif /* SEQUENTIAL_READ */ -# ifdef PNG_BENIGN_READ_ERRORS_SUPPORTED - png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; - png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; - - /* In stable builds only warn if an application error can be completely - * handled. - */ -# if PNG_RELEASE_BUILD - png_ptr->flags |= PNG_FLAG_APP_ERRORS_WARN; -# endif -# endif /* BENIGN_READ_ERRORS */ - # ifdef PNG_READ_GAMMA_SUPPORTED /* Default gamma correction values: */ # if 0 /*NYI*/ - png_ptr->gamma_accuracy = PNG_DEFAULT_GAMMA_ACCURACY; + png_ptr->gamma_accuracy = PNG_DEFAULT_GAMMA_ACCURACY; # endif /*NYI*/ png_ptr->gamma_threshold = PNG_GAMMA_THRESHOLD_FIXED; # endif /* READ_GAMMA */ @@ -178,8 +121,7 @@ png_read_chunk_header(png_structrp png_ptr) (unsigned long)png_ptr->chunk_length); /* Reset the crc and run it over the chunk name. */ - png_reset_crc(png_ptr); - png_calculate_crc(png_ptr, buf + 4, 4); + png_reset_crc(png_ptr, buf + 4); #ifdef PNG_IO_STATE_SUPPORTED png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA; diff --git a/pngrutil.c b/pngrutil.c index a6df46180..4538b6ca5 100644 --- a/pngrutil.c +++ b/pngrutil.c @@ -138,50 +138,10 @@ png_crc_read(png_structrp png_ptr, png_voidp buf, png_uint_32 length) png_calculate_crc(png_ptr, buf, length); } -/* Compare the CRC stored in the PNG file with that calculated by libpng from - * the data it has read thus far. - */ -static int -png_crc_error(png_structrp png_ptr) -{ - png_byte crc_bytes[4]; - png_uint_32 crc; - int need_crc = 1; - - if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name)) - { - if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == - (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) - need_crc = 0; - } - - else /* critical */ - { - if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) - need_crc = 0; - } - -#ifdef PNG_IO_STATE_SUPPORTED - png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC; -#endif - - /* The chunk CRC must be serialized in a single I/O call. */ - png_read_data(png_ptr, crc_bytes, 4); - - if (need_crc != 0) - { - crc = png_get_uint_32(crc_bytes); - return ((int)(crc != png_ptr->crc)); - } - - else - return (0); -} - -/* Optionally skip data and then check the CRC. Depending on whether we - * are reading an ancillary or critical chunk, and how the program has set - * things up, we may calculate the CRC on the data and print a message. - * Returns '1' if there was a CRC error, '0' otherwise. +/* Optionally skip data and then check the CRC. Depending on whether we are + * reading an ancillary or critical chunk, and how the program has set things + * up, we may calculate the CRC on the data and print a message. Returns true + * if the chunk should be discarded, otherwise false. */ int /* PRIVATE */ png_crc_finish(png_structrp png_ptr, png_uint_32 skip) @@ -202,22 +162,37 @@ png_crc_finish(png_structrp png_ptr, png_uint_32 skip) png_crc_read(png_ptr, tmpbuf, len); } - if (png_crc_error(png_ptr)) + /* Compare the CRC stored in the PNG file with that calculated by libpng from + * the data it has read thus far. Do any required error handling. The + * second parameter is to allow a critical chunk (specifically PLTE) to be + * treated as ancillary. + */ { - if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) ? - (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0: - (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE) != 0) + png_byte crc_bytes[4]; + +# ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC; +# endif + + png_read_data(png_ptr, crc_bytes, 4); + + if (png_ptr->current_crc != crc_quiet_use && + png_get_uint_32(crc_bytes) != png_ptr->crc) { - png_chunk_warning(png_ptr, "CRC error"); + if (png_ptr->current_crc == crc_error_quit) + png_chunk_error(png_ptr, "CRC"); + + else + png_chunk_warning(png_ptr, "CRC"); + + /* The only way to discard a chunk at present is to issue a warning. + * TODO: quiet_discard. + */ + return png_ptr->current_crc == crc_warn_discard; } - - else - png_chunk_error(png_ptr, "CRC error"); - - return (1); } - return (0); + return 0; } #if defined(PNG_READ_iCCP_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) ||\ @@ -314,8 +289,7 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) defined(PNG_MAXIMUM_INFLATE_WINDOW) int window_bits; - if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) == - PNG_OPTION_ON) + if (png_ptr->maximum_inflate_window) window_bits = 15; else @@ -870,6 +844,7 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr) #ifndef PNG_READ_OPT_PLTE_SUPPORTED if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) { + /* Skip the whole chunk: */ png_handle_skip(png_ptr); return; } @@ -910,45 +885,7 @@ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr) palette[i].blue = buf[2]; } - /* If we actually need the PLTE chunk (ie for a paletted image), we do - * whatever the normal CRC configuration tells us. However, if we - * have an RGB image, the PLTE can be considered ancillary, so - * we will act as though it is. - */ -#ifndef PNG_READ_OPT_PLTE_SUPPORTED - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) -#endif - png_crc_finish(png_ptr, length - num * 3U); - -#ifndef PNG_READ_OPT_PLTE_SUPPORTED - else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */ - { - /* If we don't want to use the data from an ancillary chunk, - * we have two options: an error abort, or a warning and we - * ignore the data in this chunk (which should be OK, since - * it's considered ancillary for a RGB or RGBA image). - * - * IMPLEMENTATION NOTE: this is only here because png_crc_finish uses the - * chunk type to determine whether to check the ancillary or the critical - * flags. - */ - if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE)) - { - if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) - return; - - else - png_chunk_error(png_ptr, "CRC error"); - } - - /* Otherwise, we (optionally) emit a warning and use the chunk. */ - else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) - { - png_chunk_warning(png_ptr, "CRC error"); - } - } -#endif /* READ_OPT_PLTE */ - + png_crc_finish(png_ptr, length - num * 3U); png_set_PLTE(png_ptr, info_ptr, palette, num); /* Ok, make our own copy since the set succeeded: */ @@ -1351,8 +1288,12 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr) profile + (sizeof profile_header) + 12 * tag_count, &size, 1/*finish*/); - if (length > 0 && !(png_ptr->flags & - PNG_FLAG_BENIGN_ERRORS_WARN)) + if (length > 0 +# ifdef PNG_BENIGN_READ_ERRORS_SUPPORTED + && png_ptr->benign_error_action == + PNG_ERROR +# endif /* BENIGN_READ_ERRORS */ + ) errmsg = "extra compressed data"; /* But otherwise allow extra data: */ @@ -3818,17 +3759,28 @@ png_inflate_IDAT(png_structrp png_ptr, int finish, /* This is the error return case; there was missing data, or an error. * Either continue with a warning (once; hence the zstream_error flag) - * or png_error. The 'warn' setting has to be turned on and benign errors - * have to be turned off (made warnings.) The logic of this is that this - * is a pretty serious error; PNG is about images and we don't know that the - * image is correct. + * or png_error. */ if (!png_ptr->zstream_error) /* first time */ { - if ((png_ptr->flags & PNG_FLAG_IDAT_ERRORS_WARN) != 0) - png_chunk_benign_error(png_ptr, png_ptr->zstream.msg); - else +# ifdef PNG_BENIGN_READ_ERRORS_SUPPORTED + switch (png_ptr->IDAT_error_action) + { + case PNG_ERROR: + png_chunk_error(png_ptr, png_ptr->zstream.msg); + break; + + case PNG_WARN: + png_chunk_warning(png_ptr, png_ptr->zstream.msg); + break; + + default: /* ignore */ + /* Keep going */ + break; + } +# else png_chunk_error(png_ptr, png_ptr->zstream.msg); +# endif /* !BENIGN_ERRORS */ /* And prevent the report about too many IDATs on streams with internal * LZ errors: @@ -4587,4 +4539,177 @@ png_read_update_info(png_structrp png_ptr, png_inforp info_ptr) } } +png_int_32 /* PRIVATE */ +png_read_setting(png_structrp png_ptr, png_uint_32 setting, + png_uint_32 parameter, png_int_32 value) +{ + /* Caller checks the arguments for basic validity */ + int only_get = (setting & PNG_SF_GET) != 0U; + + if (only_get) /* spurious: in case it isn't used */ + setting &= ~PNG_SF_GET; + + switch (setting) + { +# ifdef PNG_SEQUENTIAL_READ_SUPPORTED + case PNG_SR_COMPRESS_buffer_size: + if (parameter > 0 && parameter <= ZLIB_IO_MAX) + { + png_ptr->IDAT_size = parameter; + return 0; /* Cannot return a 32-bit value */ + } + + else + return PNG_EINVAL; +# endif /* SEQUENTIAL_READ */ + +# ifdef PNG_READ_GAMMA_SUPPORTED + case PNG_SR_GAMMA_threshold: + if (parameter <= 0xFFFF) + { + if (!only_get) + png_ptr->gamma_threshold = PNG_UINT_16(parameter); + + return (png_int_32)/*SAFE*/parameter; + } + + return PNG_EDOM; + +#if 0 /*NYI*/ + case PNG_SR_GAMMA_accuracy: + if (parameter <= 1600) + { + if (!only_get) + png_ptr->gamma_accuracy = parameter; + + return (png_int_32)/*SAFE*/parameter; + } + + return PNG_EDOM; +#endif /*NYI*/ +# endif /* READ_GAMMA */ + + case PNG_SR_CRC_ACTION: + /* Tell libpng how we react to CRC errors in critical chunks */ + switch (parameter) + { + case PNG_CRC_NO_CHANGE: /* Leave setting as is */ + break; + + case PNG_CRC_WARN_USE: /* Warn/use data */ + png_ptr->critical_crc = crc_warn_use; + break; + + case PNG_CRC_QUIET_USE: /* Quiet/use data */ + png_ptr->critical_crc = crc_quiet_use; + break; + + default: + case PNG_CRC_WARN_DISCARD: /* Not valid for critical data */ + return PNG_EINVAL; + + case PNG_CRC_ERROR_QUIT: /* Error/quit */ + case PNG_CRC_DEFAULT: + png_ptr->critical_crc = crc_error_quit; + break; + } + + /* Tell libpng how we react to CRC errors in ancillary chunks */ + switch (value) + { + case PNG_CRC_NO_CHANGE: /* Leave setting as is */ + break; + + case PNG_CRC_WARN_USE: /* Warn/use data */ + png_ptr->ancillary_crc = crc_warn_use; + break; + + case PNG_CRC_QUIET_USE: /* Quiet/use data */ + png_ptr->ancillary_crc = crc_quiet_use; + break; + + case PNG_CRC_ERROR_QUIT: /* Error/quit */ + png_ptr->ancillary_crc = crc_error_quit; + break; + + case PNG_CRC_WARN_DISCARD: /* Warn/discard data */ + case PNG_CRC_DEFAULT: + png_ptr->ancillary_crc = crc_warn_discard; + break; + + default: + return PNG_EINVAL; + } + + return 0; /* success */ + +# ifdef PNG_SET_OPTION_SUPPORTED + case PNG_SRW_OPTION: + switch (parameter) + { + case PNG_MAXIMUM_INFLATE_WINDOW: + if (png_ptr->maximum_inflate_window) + { + if (!value && !only_get) + png_ptr->maximum_inflate_window = 0U; + return PNG_OPTION_ON; + } + + else + { + if (value && !only_get) + png_ptr->maximum_inflate_window = 1U; + return PNG_OPTION_OFF; + } + + default: + return PNG_OPTION_UNSET; + } +# endif /* SET_OPTION */ + +# ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED + case PNG_SRW_CHECK_FOR_INVALID_INDEX: + /* The 'enabled' value is a FORTRAN style three-state: */ + if (value > 0) + png_ptr->palette_index_check = PNG_PALETTE_CHECK_ON; + + else if (value < 0) + png_ptr->palette_index_check = PNG_PALETTE_CHECK_OFF; + + else + png_ptr->palette_index_check = PNG_PALETTE_CHECK_DEFAULT; + + return 0; +# endif /* READ_CHECK_FOR_INVALID_INDEX */ + +# ifdef PNG_BENIGN_READ_ERRORS_SUPPORTED + case PNG_SRW_ERROR_HANDLING: + /* The parameter is a bit mask of what to set, the value is what to + * set it to. + */ + if (value >= PNG_IGNORE && value <= PNG_ERROR && + parameter <= PNG_ALL_ERRORS) + { + if ((parameter & PNG_BENIGN_ERRORS) != 0U) + png_ptr->benign_error_action = value & 0x3U; + + if ((parameter & PNG_APP_WARNINGS) != 0U) + png_ptr->app_warning_action = value & 0x3U; + + if ((parameter & PNG_APP_ERRORS) != 0U) + png_ptr->app_error_action = value & 0x3U; + + if ((parameter & PNG_IDAT_ERRORS) != 0U) + png_ptr->IDAT_error_action = value & 0x3U; + + return 0; + } + + return PNG_EINVAL; +# endif /* BENIGN_READ_ERRORS */ + + default: + return PNG_ENOSYS; /* not supported (whatever it is) */ + } +} #endif /* READ */ diff --git a/pngset.c b/pngset.c index e428cca1c..ef0ed78ec 100644 --- a/pngset.c +++ b/pngset.c @@ -1670,27 +1670,4 @@ png_set_chunk_malloc_max (png_structrp png_ptr, png_ptr->user_chunk_malloc_max = user_chunk_malloc_max; } #endif /* ?SET_USER_LIMITS */ - - -#ifdef PNG_BENIGN_ERRORS_SUPPORTED -void PNGAPI -png_set_benign_errors(png_structrp png_ptr, int allowed) -{ - png_debug(1, "in png_set_benign_errors"); - - /* If allowed is 1, png_benign_error() is treated as a warning. - * - * If allowed is 0, png_benign_error() is treated as an error (which - * is the default behavior if png_set_benign_errors() is not called). - */ - - if (allowed != 0) - png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN | - PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN; - - else - png_ptr->flags &= PNG_BIC_MASK(PNG_FLAG_BENIGN_ERRORS_WARN | - PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN); -} -#endif /* BENIGN_ERRORS */ #endif /* READ || WRITE */ diff --git a/pngstruct.h b/pngstruct.h index c8d150366..a66df6772 100644 --- a/pngstruct.h +++ b/pngstruct.h @@ -351,6 +351,15 @@ typedef struct png_transform /* Linked list of transform functions */ } png_transform; #endif /* TRANSFORM_MECH */ +/* Action to take on CRC errors (four values) */ +typedef enum +{ + crc_error_quit = PNG_CRC_ERROR_QUIT-1, + crc_warn_discard = PNG_CRC_WARN_DISCARD-1, + crc_warn_use = PNG_CRC_WARN_USE-1, + crc_quiet_use = PNG_CRC_QUIET_USE-1 +} png_crc_action; + struct png_struct_def { /* Rearranged in libpng 1.7 to attempt to lessen padding; in general @@ -419,11 +428,6 @@ struct png_struct_def png_byte bit_depth; /* bit depth of file */ png_byte sig_bytes; /* magic bytes read/written at start of file */ - /* Options */ -#ifdef PNG_SET_OPTION_SUPPORTED - png_uint_32 options; /* On/off state (up to 16 options) */ -#endif /* SET_OPTIONS */ - #ifdef PNG_READ_SUPPORTED #if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) /* The png_struct colorspace structure is only required on read - on write it @@ -737,6 +741,28 @@ struct png_struct_def * received; set by the zstream using code for * its own purposes. [progressive read] */ # endif /* PROGRESSIVE_READ */ +# ifdef PNG_BENIGN_ERRORS_SUPPORTED + unsigned int benign_error_action :2; + unsigned int app_warning_action :2; + unsigned int app_error_action :2; +# ifdef PNG_READ_SUPPORTED + unsigned int IDAT_error_action :2; +# endif /* READ */ +# endif /* BENIGN_ERRORS */ +# ifdef PNG_READ_SUPPORTED + /* CRC checking actions, one for critical chunks, one for ancillary + * chunks. + */ + unsigned int critical_crc :2; + unsigned int ancillary_crc :2; + unsigned int current_crc :2; /* Cache of one or other of the above */ +# endif +# ifdef PNG_SET_OPTION_SUPPORTED +# ifdef PNG_READ_SUPPORTED + unsigned int maximum_inflate_window :1U; +# endif /* READ */ + unsigned int skip_sRGB_profile_check :1U; +# endif /* SET_OPTION */ /* MNG SUPPORT */ #ifdef PNG_MNG_FEATURES_SUPPORTED diff --git a/pngtrans.c b/pngtrans.c index 65828921a..098848265 100644 --- a/pngtrans.c +++ b/pngtrans.c @@ -817,47 +817,6 @@ png_get_palette_max(png_const_structrp png_ptr, png_const_inforp info_ptr) } #endif /* GET_PALETTE_MAX */ -#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED - /* Whether to report invalid palette index; added at libng-1.5.10. - * It is possible for an indexed (color-type==3) PNG file to contain - * pixels with invalid (out-of-range) indexes if the PLTE chunk has - * fewer entries than the image's bit-depth would allow. We recover - * from this gracefully by filling any incomplete palette with zeros - * (opaque black). By default, when this occurs libpng will issue - * an error. This API can be used to override that behavior. - */ -void PNGAPI -png_set_check_for_invalid_index(png_structrp png_ptr, int enabled) -{ - /* This defaults to 0, therefore *on*: */ - if (png_ptr != NULL) - { - if (png_ptr->read_struct) - { -# ifndef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED - png_app_error(png_ptr, "no read palette check support"); - return; -# endif /* !READ_CHECK_FOR_INVALID_INDEX */ - } - - else /* write struct */ - { -# ifndef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED - png_app_error(png_ptr, "no write palette check support"); - return; -# endif /* !WRITE_CHECK_FOR_INVALID_INDEX */ - } - - if (enabled > 0) - png_ptr->palette_index_check = PNG_PALETTE_CHECK_ON; - else if (enabled < 0) - png_ptr->palette_index_check = PNG_PALETTE_CHECK_OFF; - else - png_ptr->palette_index_check = PNG_PALETTE_CHECK_DEFAULT; - } -} -#endif /* CHECK_FOR_INVALID_INDEX */ - void /* PRIVATE */ png_init_row_info(png_structrp png_ptr) { diff --git a/pngwrite.c b/pngwrite.c index 044c95c89..0807791ff 100644 --- a/pngwrite.c +++ b/pngwrite.c @@ -538,24 +538,28 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, if (png_ptr != NULL) { - /* This is a highly dubious configuration option; by default it is off, - * but it may be appropriate for private builds that are testing - * extensions not conformant to the current specification, or of - * applications that must not fail to write at all costs! - */ -#ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED - /* In stable builds only warn if an application error can be completely - * handled. - */ - png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; -#endif - - /* App warnings are warnings in release (or release candidate) builds but - * are errors during development. - */ -#if PNG_RELEASE_BUILD - png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; -#endif +# ifdef PNG_BENIGN_ERRORS_SUPPORTED +# if !PNG_RELEASE_BUILD + /* Always quit on error prior to release */ + png_ptr->benign_error_action = PNG_ERROR; + png_ptr->app_warning_action = PNG_ERROR; + png_ptr->app_error_action = PNG_ERROR; +# else /* RELEASE_BUILD */ + /* Allow benign errors on write, subject to app control. */ +# ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED + png_ptr->benign_error_action = PNG_WARN; + png_ptr->app_error_action = PNG_WARN; + png_ptr->app_warning_action = PNG_WARN; +# else /* !BENIGN_WRITE_ERRORS */ + /* libpng build without benign error support; the application + * author has to be assumed to be correct, so: + */ + png_ptr->benign_error_action = PNG_ERROR; + png_ptr->app_warning_action = PNG_ERROR; + png_ptr->app_error_action = PNG_ERROR; +# endif /* !BENIGN_WRITE_ERRORS */ +# endif /* RELEASE_BUILD */ +# endif /* BENIGN_ERRORS */ } return png_ptr; diff --git a/pngwutil.c b/pngwutil.c index 678daa210..23159308a 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -99,9 +99,7 @@ png_write_chunk_header(png_structrp png_ptr, png_uint_32 chunk_name, png_ptr->chunk_name = chunk_name; /* Reset the crc and run it over the chunk name */ - png_reset_crc(png_ptr); - - png_calculate_crc(png_ptr, buf + 4, 4); + png_reset_crc(png_ptr, buf+4); #ifdef PNG_IO_STATE_SUPPORTED /* Inform the I/O callback that chunk data will (possibly) be written. @@ -1002,10 +1000,9 @@ png_deflate_destroy(png_structrp png_ptr) #define pz_strategy_pos 3 #define pz_zlib_bits 0xFFFFU /* Anything below this is not used directly by zlib: */ -#define pz_png_level_base (-1) /* libpng equivalent of zlib level */ -#define pz_png_level_max 10 +#define pz_png_level_base 0 +#define pz_png_level_max 6 #define pz_png_level_pos 4 -#define PNG_WRITE_DEFAULT_LEVEL 6 /* TEMPORARY: move to pnglibconf.dfa */ #define pz_offset(name) (pz_ ## name ## _base - 1) /* setting_value == pz_offset(setting)+encoded_value */ @@ -1037,6 +1034,112 @@ png_deflate_destroy(png_structrp png_ptr) ((value) >= pz_min(name) && (value) <= pz_max(name) ?\ pz_encode(name, value) : 0)) +static png_int_32 +pz_compression_setting(png_structrp png_ptr, png_uint_32 owner, + int min, int max, int shift, png_int_32 value, int only_get) + /* This is a support function for png_write_setting below. */ +{ + png_zlib_statep ps; + png_uint_32p psettings; + + /* The value is only required for a 'set', eliminate out-of-range values + * first: + */ + if (!only_get && (value < min || value > max)) + return PNG_EDOM; + + /* If setting a value make sure the state exists: */ + if (!only_get) + ps = get_zlib_state(png_ptr); + + else if (owner != 0U) /* ps may be NULL */ + ps = png_ptr->zlib_state; + + else /* get and owner is 0U */ + return 0; /* supported */ + + psettings = NULL; + switch (owner) + { + png_int_32 res; + + case png_IDAT: + if (ps != NULL) psettings = &ps->pz_IDAT; + break; + + case png_iCCP: + if (ps != NULL) psettings = &ps->pz_iCCP; + break; + + case 0U: + /* All the settings. At this point the 'get' case has returned 0 + * above, the value has been checked and the paramter is 0, therefore + * valid. Each of the following calls should succeed and it would be + * reasonable to eliminate the PNG_FAILED tests in a world where + * software engineers never made mistakes. + */ + res = pz_compression_setting(png_ptr, png_IDAT, min, max, shift, + value, 0/*set*/); + + if (PNG_FAILED(res)) + return res; + + res = pz_compression_setting(png_ptr, png_iCCP, min, max, shift, + value, 0/*set*/); + + if (PNG_FAILED(res)) + return res; + + /* The text settings are only changed if the system builder didn't + * disable the API to change them. Perhaps this API shouldn't exist? + */ + res = pz_compression_setting(png_ptr, png_iCCP, min, max, shift, + value, 0/*set*/); + + if (PNG_FAILED(res)) + return res; + + return 0; + + + case png_zTXt: + case png_iTXt: + if (ps != NULL) psettings = &ps->pz_text; + break; + + default: + /* Return PNG_ENOSYS, not PNG_EINVAL, to support future addition of new + * compressed chunks and the fact that zTXt and iTXt customization can + * be disabled. + */ + return PNG_ENOSYS; + } + + if (psettings == NULL) + return PNG_UNSET; /* valid setting that is not set */ + + { + png_uint_32 settings = *psettings; + png_uint_32 mask = 0xFU << shift; + + if (!only_get) + *psettings = (settings & ~mask) + + ((png_uint_32)/*SAFE*/(value-min+1) << shift); + + settings &= mask; + + if (settings == 0U) + return PNG_UNSET; + + else + return (int)/*SAFE*/((settings >> shift)-1U) + min; + } +} + +#define compression_setting(pp, owner, setting, value, get)\ + pz_compression_setting(pp, owner, pz_min(setting), pz_max(setting),\ + pz_shift(setting), value, get) + /* There is (as of zlib 1.2.8) a bug in the implementation of compression with a * window size of 256 which zlib works round by resetting windowBits from 8 to 9 * whenever deflateInit2 is called with that value. Fix this up here. @@ -1089,11 +1192,12 @@ fix_cinfo(png_zlib_statep ps, png_bytep data, png_alloc_size_t data_size) debug(pz_get(ps, current, windowBits, 0) == windowBits); if (data_size <= half_window_size /* Can shrink */ && - pz_get(ps, IDAT, png_level, PNG_WRITE_DEFAULT_LEVEL) == -1) + pz_get(ps, IDAT, png_level, PNG_DEFAULT_COMPRESSION_LEVEL) == + PNG_COMPRESSION_COMPAT) { unsigned int d1; - /* Before 1.7 libpng overrode a user-supplied windowBits if the data + /* Before 1.7.0 libpng overrode a user-supplied windowBits if the data * was smaller. */ do @@ -1134,7 +1238,7 @@ pz_default_settings(png_uint_32 settings, const png_uint_32 owner, */ if (!pz_isset(png_level, settings)) { - png_level = PNG_WRITE_DEFAULT_LEVEL; + png_level = PNG_DEFAULT_COMPRESSION_LEVEL; settings |= pz_encode(png_level, png_level); } @@ -1149,7 +1253,7 @@ pz_default_settings(png_uint_32 settings, const png_uint_32 owner, { switch (png_level) { - case -1: /* Legacy setting */ + case PNG_COMPRESSION_COMPAT: /* Legacy setting */ /* The pre-1.7 code used Z_FILTERED normally but uses * Z_DEFAULT_STRATEGY for palette or low-bit-depth images. * @@ -1168,15 +1272,21 @@ pz_default_settings(png_uint_32 settings, const png_uint_32 owner, strategy = Z_FILTERED; break; - case 1: /* ultra-fast */ - case 2: + case PNG_COMPRESSION_LOW_MEMORY: + /* Reduce memory at all costs: */ + strategy = Z_HUFFMAN_ONLY; + break; + + case PNG_COMPRESSION_HIGH_SPEED: /* RLE is as fast as HUFFMAN_ONLY and can reduce size a lot in a few * cases. */ strategy = Z_RLE; break; - case 3: case 4: case 5: case 6: + default: /* For GCC */ + case PNG_COMPRESSION_LOW: + case PNG_COMPRESSION_MEDIUM: /* Z_FILTERED is almost as good as the default and can be * significantly faster, it biases the algorithm towards smaller * byte values. @@ -1205,11 +1315,16 @@ pz_default_settings(png_uint_32 settings, const png_uint_32 owner, strategy = Z_DEFAULT_STRATEGY; else /* text chunk */ - strategy = Z_DEFAULT_STRATEGY; /* TODO: check data_size */ + strategy = Z_FILTERED; /* Always better for some reason */ break; - default: /* includes the 'no compression' option */ - strategy = Z_DEFAULT_STRATEGY; + case PNG_COMPRESSION_HIGH_READ_SPEED: + case PNG_COMPRESSION_HIGH: + if (owner == png_IDAT || owner == png_iCCP) + strategy = Z_DEFAULT_STRATEGY; + + else + strategy = Z_FILTERED; break; } @@ -1272,14 +1387,31 @@ pz_default_settings(png_uint_32 settings, const png_uint_32 owner, * compression only varies slightly (under 8%) across the level * range. */ - if (png_level < 0) /* Legacy, or error */ - zlib_level = Z_DEFAULT_COMPRESSION; /* NOTE: -1 */ + switch (png_level) + { + case PNG_COMPRESSION_COMPAT: + zlib_level = Z_DEFAULT_COMPRESSION; /* NOTE: -1 */ + break; - else if (png_level < 9) - zlib_level = png_level; + case PNG_COMPRESSION_LOW_MEMORY: + case PNG_COMPRESSION_HIGH_SPEED: + zlib_level = 1; + break; - else /* PNG compression level 10; the ridiculous level */ - zlib_level = 9; + default: /* For GCC */ + case PNG_COMPRESSION_LOW: + zlib_level = 3; + break; + + case PNG_COMPRESSION_MEDIUM: + zlib_level = 6; /* Old default! */ + break; + + case PNG_COMPRESSION_HIGH_READ_SPEED: + case PNG_COMPRESSION_HIGH: + zlib_level = 9; + break; + } break; } @@ -1295,7 +1427,7 @@ pz_default_settings(png_uint_32 settings, const png_uint_32 owner, */ if (!pz_isset(windowBits, settings)) { - if (png_level == -1/* Legacy */) + if (png_level == PNG_COMPRESSION_COMPAT/* Legacy */) { /* This is the libpng16 calculation (it is wrong; a misunderstanding of * what zlib actually requires!) @@ -1324,12 +1456,22 @@ pz_default_settings(png_uint_32 settings, const png_uint_32 owner, } } - else if (zlib_level == Z_NO_COMPRESSION) + /* The window size affects the memory used on both read and write but also + * the time on write (but not normally read). Handle the low memory + * requirement first: + */ + else if (zlib_level == Z_NO_COMPRESSION || + png_level == PNG_COMPRESSION_LOW_MEMORY) windowBits = 8; /* If the strategy has been set to something that doesn't benefit from * higher windowBits values take advantage of this. Note that pz_value * returns an invalid value if pz_isset is false. + * + * The only png_level that affects this decision is HIGH_SPEED, because + * a smaller windowBits should speed up the search, however the code above + * chose zlib_level based on this so ignore that consideration and just + * use zlib_level below. */ else switch (strategy) { @@ -1363,7 +1505,7 @@ pz_default_settings(png_uint_32 settings, const png_uint_32 owner, */ case Z_FILTERED: /* The Z_FILTERED case changes suddenly at (zlib) level 4 to - * benefitt from looking at all the data: + * benefit from looking at all the data: */ if (zlib_level < 4 && zlib_level != Z_DEFAULT_COMPRESSION/*-1: 6*/) test_size = data_size / 8U; @@ -1442,8 +1584,8 @@ pz_default_settings(png_uint_32 settings, const png_uint_32 owner, /* For memLevel this just increases the memory used but can help with the * Huffman code generation even to level 9 (the maximum), so just set the - * max. This affects memory used, not (apparently) compression speed so apps - * with limited memory requirements may need to override it. + * max. This affects memory used, not (apparently) compression speed so + * the only relevant png_level is LOW_MEMORY. * * The legacy setting is '8'; this is the level that Zlib defaults to because * 16-bit iAPX86 systems could not handle '9'. Because MAX_MEM_LEVEL is used @@ -1456,8 +1598,26 @@ pz_default_settings(png_uint_32 settings, const png_uint_32 owner, * sizes is interesting.) */ if (!pz_isset(memLevel, settings)) - settings |= pz_encode(memLevel, - png_level == -1 ? 8 : MAX_MEM_LEVEL/*from zconf.h*/); + { + int memLevel; + + switch (png_level) + { + case PNG_COMPRESSION_COMPAT: + memLevel = 8; + break; + + case PNG_COMPRESSION_LOW_MEMORY: + memLevel = 1; + break; + + default: + memLevel = MAX_MEM_LEVEL/*from zconf.h*/; + break; + } + + settings |= pz_encode(memLevel, memLevel); + } return settings; } @@ -2898,7 +3058,8 @@ png_write_IDAT(png_structrp png_ptr, int flush) IDAT_size = png_ptr->IDAT_size; if (IDAT_size == 0U) { - if (pz_get(ps, IDAT, png_level, PNG_WRITE_DEFAULT_LEVEL) != -1/*legacy*/) + if (pz_get(ps, IDAT, png_level, PNG_DEFAULT_COMPRESSION_LEVEL) != + PNG_COMPRESSION_COMPAT/*legacy*/) IDAT_size = PNG_ZBUF_SIZE; else @@ -3209,48 +3370,7 @@ png_write_end_row(png_structrp png_ptr, int flush) png_ptr->row_number = row_number; } -/* This returns the zlib compression state for APIs that may be called before - * the first call to png_write_row (so when the state might not exist). It - * performs initialization as required. - */ -#if defined(PNG_WRITE_FLUSH_SUPPORTED) || defined(PNG_WRITE_FILTER_SUPPORTED)\ - || defined(PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED)\ - || defined(PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED) -static png_zlib_statep -png_get_zlib_state(png_structrp png_ptr) -{ - if (png_ptr != NULL) - { - if (png_ptr->read_struct) - png_app_warning(png_ptr, "write API called on read"); - - else - return get_zlib_state(png_ptr); - } - - return NULL; -} -#endif /* things that need it */ - #ifdef PNG_WRITE_FLUSH_SUPPORTED -/* Set the automatic flush interval or 0 to turn flushing off */ -void PNGAPI -png_set_flush(png_structrp png_ptr, int nrows) -{ - png_zlib_statep ps = png_get_zlib_state(png_ptr); - - png_debug(1, "in png_set_flush"); - - if (ps != NULL) - { - if (nrows <= 0) - ps->flush_dist = 0xEFFFFFFFU; - - else - ps->flush_dist = nrows; - } -} - /* Flush the current output buffers now */ void PNGAPI png_write_flush(png_structrp png_ptr) @@ -3506,60 +3626,33 @@ filter_row(png_structrp png_ptr, png_const_bytep prev_row, } /* Allow the application to select one or more row filters to use. */ -void PNGAPI -png_set_filter(png_structrp png_ptr, int method, int filtersIn) +static png_int_32 +set_filter(png_zlib_statep ps, unsigned int filtersIn) { - png_zlib_statep ps = png_get_zlib_state(png_ptr); - - png_debug(1, "in png_set_filter"); - - if (ps == NULL) - return; - - /* See png_write_IHDR above; this limits the filter method to one of the - * values permitted in png_write_IHDR unless that has not been called in - * which case only the 'base' method is permitted because that is the initial - * value of png_struct::filter_method (i.e. 0). + /* Notice that PNG_NO_FILTERS is 0 and passes this test; this is OK because + * filters then gets set to PNG_FILTER_NONE, as is required. + * + * The argument to this routine is actually an (int), but convertion to + * (unsigned int) is safe because it leaves the top bits set which results in + * PNG_EDOM below. */ - if (method != png_ptr->filter_method) - { - ps->filter_mask = 0U; /* safety: uninitialized */ - png_app_error(png_ptr, "png_set_filter: method does not match IHDR"); - return; - } - - /* Notice that PNG_NO_FILTERS is 0 and passes this test; this is OK - * because filters then gets set to PNG_FILTER_NONE, as is required. - */ - if (filtersIn >= 0 && filtersIn < PNG_FILTER_NONE) + if (filtersIn < PNG_FILTER_NONE) filtersIn = PNG_FILTER_MASK(filtersIn); /* PNG_ALL_FILTERS is a constant, unfortunately it is nominally signed, for - * historical reasons, hence the 'unsigned' here. The '&' can be omitted - * anyway because of the check. + * historical reasons, hence the PNG_BIC_MASK here. */ - if ((filtersIn & PNG_BIC_MASK(PNG_ALL_FILTERS)) == 0) + if ((filtersIn & PNG_BIC_MASK(PNG_ALL_FILTERS)) == 0U) { # ifndef PNG_SELECT_FILTER_SUPPORTED - if ((filtersIn & (filtersIn-1)) != 0) /* remove LSBit */ - { - png_app_warning(png_ptr, - "png_set_filter: filter selection not supported"); - filtersIn &= -filtersIn; /* Use lowest set bit */ - } + filtersIn &= -filtersIn; /* Use lowest set bit */ # endif /* !SELECT_FILTER */ - ps->filter_mask = filtersIn & (unsigned)PNG_ALL_FILTERS; + return ps->filter_mask = filtersIn & PNG_ALL_FILTERS; } - else - { - /* Prior to 1.7.0 this ignored the error and just used the bits that - * are present, now it resets to the uninitialized value: - */ - ps->filter_mask = 0U; /* safety: uninitialized */ - png_app_error(png_ptr, "png_set_filter: invalid filter mask/value"); - } + else /* Out-of-range filtersIn: */ + return PNG_EDOM; } #endif /* WRITE_FILTER */ @@ -3580,7 +3673,7 @@ png_write_start_IDAT(png_structrp png_ptr) png_zlib_state_set_buffer_limits(png_ptr, ps); /* Now default the filter mask if it hasn't been set already: */ - png_level = pz_get(ps, IDAT, png_level, PNG_WRITE_DEFAULT_LEVEL); + png_level = pz_get(ps, IDAT, png_level, PNG_DEFAULT_COMPRESSION_LEVEL); if (ps->filter_mask == 0) { @@ -3657,7 +3750,7 @@ png_write_start_IDAT(png_structrp png_ptr) if (ps->write_row_size == 0U /* row cannot be buffered */) ps->filter_mask = PNG_FILTER_NONE; - else if (png_level == -1/* Legacy */) + else if (png_level == PNG_COMPRESSION_COMPAT/* Legacy */) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || png_ptr->bit_depth < 8U) @@ -3673,8 +3766,16 @@ png_write_start_IDAT(png_structrp png_ptr) * <=128 (which means <=129 bytes per row with the filter byte) the * resultant inclusion of 32x32 RGBA images results in significantly * increased compressed size. + * + * The test on png_level captures the following settings: + * + * PNG_COMPRESSION_LOW_MEMORY + * PNG_COMPRESSION_HIGH_SPEED + * PNG_COMPRESSION_HIGH_READ_SPEED + * + * NOTE: this relies on the exact values in png.h! */ - else if ((png_level >= 0 && png_level <= 2) /* 0, 1, 2 */ + else if (png_level <= PNG_COMPRESSION_HIGH_READ_SPEED || png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || png_ptr->bit_depth < 8U || ps->write_row_size/*does not include filter*/ < 128U @@ -3684,14 +3785,18 @@ png_write_start_IDAT(png_structrp png_ptr) /* ELSE: there are at least 128 bytes in every row and the pixels * are multiples of a byte. */ - else if (png_level <= 4) /* 3, 4 */ - ps->filter_mask = PNG_FILTER_NONE+PNG_FILTER_SUB; + else switch (png_level) + { + default: /* For GCC */ + case PNG_COMPRESSION_LOW: + ps->filter_mask = PNG_FILTER_NONE+PNG_FILTER_SUB; - else if (png_level <= 6) /* 5, 6 */ - ps->filter_mask = PNG_FAST_FILTERS; + case PNG_COMPRESSION_MEDIUM: + ps->filter_mask = PNG_FAST_FILTERS; - else /* 7, 8, 9 */ - ps->filter_mask = PNG_ALL_FILTERS; + case PNG_COMPRESSION_HIGH: + ps->filter_mask = PNG_ALL_FILTERS; + } # else /* !SELECT_FILTER */ ps->filter_mask = PNG_FILTER_NONE; # endif /* !SELECT_FILTER */ @@ -3857,7 +3962,8 @@ png_start_filter_select(png_zlib_statep ps, unsigned int bpp) if (fs != NULL) { png_uint_32 window = ps->filter_select_window; - fs->png_level = pz_get(ps, IDAT, png_level, PNG_WRITE_DEFAULT_LEVEL); + fs->png_level = pz_get(ps, IDAT, png_level, + PNG_DEFAULT_COMPRESSION_LEVEL); /* Delay initialize this here: */ if (window < 3U || window > PNG_FILTER_SELECT_WINDOW_MAX) @@ -4766,153 +4872,146 @@ png_write_png_data(png_structrp png_ptr, png_bytep prev_pixels, } #endif /* !WRITE_FILTER */ -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* GRR 970116 */ -/* Legacy API that weighted the filter metric by the number of times it had been - * used before. - */ -#ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_FUNCTION(void,PNGAPI -png_set_filter_heuristics,(png_structrp png_ptr, int heuristic_method, - int num_weights, png_const_doublep filter_weights, - png_const_doublep filter_costs),PNG_DEPRECATED) +png_int_32 /* PRIVATE */ +png_write_setting(png_structrp png_ptr, png_uint_32 setting, + png_uint_32 parameter, png_int_32 value) { - png_app_warning(png_ptr, "weighted filter heuristics not implemented"); - PNG_UNUSED(heuristic_method) - PNG_UNUSED(num_weights) - PNG_UNUSED(filter_weights) - PNG_UNUSED(filter_costs) + /* Caller checks the arguments for basic validity */ + int only_get = (setting & PNG_SF_GET) != 0U; + + setting &= ~PNG_SF_GET; + + switch (setting) + { + /* Settings in png_struct: */ + case PNG_SW_IDAT_size: + if (parameter > 0 && parameter <= PNG_UINT_31_MAX) + { + if (!only_get) + png_ptr->IDAT_size = parameter; + + return 0; /* set ok */ + } + + else + return PNG_EINVAL; + + /* Settings in zlib_state: */ + case PNG_SW_COMPRESS_png_level: + return compression_setting(png_ptr, parameter, png_level, value, + only_get); + +# ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED + case PNG_SW_COMPRESS_zlib_level: + return compression_setting(png_ptr, parameter, level, value, + only_get); + + case PNG_SW_COMPRESS_windowBits: + return compression_setting(png_ptr, parameter, windowBits, value, + only_get); + + case PNG_SW_COMPRESS_memLevel: + return compression_setting(png_ptr, parameter, memLevel, value, + only_get); + + case PNG_SW_COMPRESS_strategy: + return compression_setting(png_ptr, parameter, strategy, value, + only_get); + + case PNG_SW_COMPRESS_method: + if (value != 8) /* Only supported method */ + return PNG_EINVAL; + return 8; /* old method */ +# endif /* WRITE_CUSTOMIZE_COMPRESSION */ + +# ifdef PNG_WRITE_FILTER_SUPPORTED + case PNG_SW_COMPRESS_filters: + /* The method must match that in the IHDR: */ + if (parameter == png_ptr->filter_method) + { + if (!only_get) + return set_filter(get_zlib_state(png_ptr), value); + + else if (png_ptr->zlib_state != NULL && + png_ptr->zlib_state->filter_mask != 0U/*unset*/) + return png_ptr->zlib_state->filter_mask; + + else + return PNG_UNSET; + } + + else /* Invalid filter method */ + return PNG_EINVAL; + + case PNG_SW_COMPRESS_row_buffers: + /* New in 1.7.0: direct control of the buffering. */ + switch (parameter) + { + case 0: + if (!only_get) + get_zlib_state(png_ptr)->save_row = SAVE_ROW_OFF; + return 0; + + case 1: + if (!only_get) + get_zlib_state(png_ptr)->save_row = SAVE_ROW_ON; + return 1; + + default: + return PNG_ENOSYS; /* no support for bigger values */ + } +# endif /* WRITE_FILTER */ + +# ifdef PNG_WRITE_FLUSH_SUPPORTED + case PNG_SW_FLUSH: + /* Set the automatic flush interval or 0 to turn flushing off */ + if (!only_get) + get_zlib_state(png_ptr)->flush_dist = + value <= 0 ? 0xEFFFFFFFU : (png_uint_32)/*SAFE*/value; + + return 0; +# endif /* WRITE_FLUSH */ + +# ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED + case PNG_SRW_CHECK_FOR_INVALID_INDEX: + /* The 'enabled' value is a FORTRAN style three-state: */ + if (value > 0) + png_ptr->palette_index_check = PNG_PALETTE_CHECK_ON; + + else if (value < 0) + png_ptr->palette_index_check = PNG_PALETTE_CHECK_OFF; + + else + png_ptr->palette_index_check = PNG_PALETTE_CHECK_DEFAULT; + + return 0; +# endif /* WRITE_CHECK_FOR_INVALID_INDEX */ + +# ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED + case PNG_SRW_ERROR_HANDLING: + /* The parameter is a bit mask of what to set, the value is what to + * set it to. PNG_IDAT_ERRORS is ignored on write. + */ + if (value >= PNG_IGNORE && value <= PNG_ERROR && + parameter <= PNG_ALL_ERRORS) + { + if ((parameter & PNG_BENIGN_ERRORS) != 0U) + png_ptr->benign_error_action = value & 0x3U; + + if ((parameter & PNG_APP_WARNINGS) != 0U) + png_ptr->app_warning_action = value & 0x3U; + + if ((parameter & PNG_APP_ERRORS) != 0U) + png_ptr->app_error_action = value & 0x3U; + + return 0; + } + + return PNG_EINVAL; +# endif /* BENIGN_WRITE_ERRORS */ + + default: + return PNG_ENOSYS; /* not supported (whatever it is) */ + } } -#endif /* FLOATING_POINT */ - -#ifdef PNG_FIXED_POINT_SUPPORTED -PNG_FUNCTION(void,PNGAPI -png_set_filter_heuristics_fixed,(png_structrp png_ptr, int heuristic_method, - int num_weights, png_const_fixed_point_p filter_weights, - png_const_fixed_point_p filter_costs),PNG_DEPRECATED) -{ - png_app_warning(png_ptr, "weighted filter heuristics not implemented"); - PNG_UNUSED(heuristic_method) - PNG_UNUSED(num_weights) - PNG_UNUSED(filter_weights) - PNG_UNUSED(filter_costs) -} -#endif /* FIXED_POINT */ -#endif /* WRITE_WEIGHTED_FILTER */ - -#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED -void PNGAPI -png_set_compression_level(png_structrp png_ptr, int level) -{ - png_zlib_statep ps = png_get_zlib_state(png_ptr); - - png_debug(1, "in png_set_compression_level"); - - if (ps != NULL) - pz_assign(ps, IDAT, level, level); -} - -void PNGAPI -png_set_compression_mem_level(png_structrp png_ptr, int mem_level) -{ - png_zlib_statep ps = png_get_zlib_state(png_ptr); - - png_debug(1, "in png_set_compression_mem_level"); - - if (ps != NULL) - pz_assign(ps, IDAT, memLevel, mem_level); -} - -void PNGAPI -png_set_compression_strategy(png_structrp png_ptr, int strategy) -{ - png_zlib_statep ps = png_get_zlib_state(png_ptr); - - png_debug(1, "in png_set_compression_strategy"); - - if (ps != NULL) - pz_assign(ps, IDAT, 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_structrp png_ptr, int window_bits) -{ - png_zlib_statep ps = png_get_zlib_state(png_ptr); - - if (ps != NULL) - pz_assign(ps, IDAT, windowBits, window_bits); -} - -void PNGAPI -png_set_compression_method(png_structrp png_ptr, int method) -{ - png_debug(1, "in png_set_compression_method"); - - /* This used to just warn, this seems unhelpful and might result in bogus - * PNG files if zlib starts accepting other methods. - */ - if (method != 8) - png_app_error(png_ptr, "Only compression method 8 is supported by PNG"); -} -#endif /* WRITE_CUSTOMIZE_COMPRESSION */ - -/* The following were added to libpng-1.5.4 */ -#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED -void PNGAPI -png_set_text_compression_level(png_structrp png_ptr, int level) -{ - png_zlib_statep ps = png_get_zlib_state(png_ptr); - - png_debug(1, "in png_set_text_compression_level"); - - if (ps != NULL) - pz_assign(ps, text, level, level); -} - -void PNGAPI -png_set_text_compression_mem_level(png_structrp png_ptr, int mem_level) -{ - png_zlib_statep ps = png_get_zlib_state(png_ptr); - - png_debug(1, "in png_set_text_compression_mem_level"); - - if (ps != NULL) - pz_assign(ps, text, memLevel, mem_level); -} - -void PNGAPI -png_set_text_compression_strategy(png_structrp png_ptr, int strategy) -{ - png_zlib_statep ps = png_get_zlib_state(png_ptr); - - png_debug(1, "in png_set_text_compression_strategy"); - - if (ps != NULL) - pz_assign(ps, 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_structrp png_ptr, int window_bits) -{ - png_zlib_statep ps = png_get_zlib_state(png_ptr); - - if (ps != NULL) - pz_assign(ps, text, windowBits, window_bits); -} - -void PNGAPI -png_set_text_compression_method(png_structrp png_ptr, int method) -{ - png_debug(1, "in png_set_text_compression_method"); - - if (method != 8) - png_app_error(png_ptr, "Only compression method 8 is supported by PNG"); -} -#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ -/* end of API added to libpng-1.5.4 */ #endif /* WRITE */ diff --git a/scripts/pnglibconf.dfa b/scripts/pnglibconf.dfa index 439febc6c..c45d6ea12 100644 --- a/scripts/pnglibconf.dfa +++ b/scripts/pnglibconf.dfa @@ -285,33 +285,16 @@ setting ZLIB_HEADER default # must be made by the user) option SET_OPTION disabled -# Run-time setting of parameters, enabled as required below -option SETTING disabled - # To support hardware specific optimizations libpng can include a hardware # specific header at build time, this setting records the included header: setting EXTENSION_HEADER -# These settings configure the default compression level (0-9) and 'strategy'; -# strategy is as defined by the implementors of zlib. It describes the input -# data and modifies the zlib parameters in an attempt to optimize the balance -# between search and huffman encoding in the zlib algorithms. The defaults are -# the zlib.h defaults - the apparently recursive definition does not arise -# because the name of the setting is prefixed by PNG_ -# -# The TEXT values are the defaults when writing compressed text (all forms) +# This setting controls the default zlib compression settings. See the +# description of the values in png.h +setting DEFAULT_COMPRESSION_LEVEL default PNG_COMPRESSION_MEDIUM # The '@' here means to substitute the value when pnglibconf.h is built setting ZLIB_VERNUM default @ZLIB_VERNUM -setting Z_DEFAULT_COMPRESSION default @Z_DEFAULT_COMPRESSION -# By experiment even if other strategies are favored over the zlib default it -# still comes out best for 47% of files tested; more than filtered, the next -# best, for 38.8% of files tested. -setting Z_DEFAULT_STRATEGY default @Z_DEFAULT_STRATEGY -setting Z_DEFAULT_NOFILTER_STRATEGY default @Z_DEFAULT_STRATEGY - -setting TEXT_Z_DEFAULT_COMPRESSION default @Z_DEFAULT_COMPRESSION -setting TEXT_Z_DEFAULT_STRATEGY default @Z_DEFAULT_STRATEGY # Define this to something that will stop, at least, the current thread; control # cannot proceed beyond the PNG_ABORT operation and compilation of pngerror.c is @@ -343,7 +326,6 @@ option WRITE_INT_FUNCTIONS disabled # # WARNINGS: normally on, if off no warnings are generated # ERROR_TEXT: normally on, if off errors happen but there is no message -# ERROR_NUMBERS: unimplemented feature, therefore disabled # BENIGN_ERRORS: support for just issuing warnings for recoverable errors # # BENIGN_READ_ERRORS: @@ -360,7 +342,6 @@ option WRITE_INT_FUNCTIONS disabled option WARNINGS option ERROR_TEXT -option ERROR_NUMBERS disabled option BENIGN_ERRORS option BENIGN_WRITE_ERRORS requires BENIGN_ERRORS disabled @@ -515,7 +496,7 @@ option READ_QUANTIZE requires READ_TRANSFORMS enables TRANSFORM_MECH # gamma processing; and it is an enormous waste of space. You just need to # remove the use of libpng APIs that depend on it. option READ_GAMMA requires READ_TRANSFORMS, READ_gAMA, READ_sRGB, - enables TRANSFORM_MECH, READ_SCALE_16_TO_8, READ_EXPAND, SETTING + enables TRANSFORM_MECH, READ_SCALE_16_TO_8, READ_EXPAND option READ_ALPHA_MODE requires READ_TRANSFORMS, READ_GAMMA, READ_BACKGROUND option READ_BACKGROUND requires READ_TRANSFORMS, READ_STRIP_ALPHA, READ_GAMMA, @@ -852,10 +833,8 @@ option WRITE_tEXt enables WRITE_TEXT option WRITE_zTXt enables WRITE_TEXT option WRITE_iTXt enables WRITE_TEXT -# This only affects support of the optional PLTE chunk in RGB and RGBA -# images. Notice that READ_ANCILLARY_CHUNKS therefore disables part -# of the regular chunk reading too. - +# WARNING: unless this option is set PLTE chunks in non-palette images are +# simply discarded (with checking of the CRC, but nothing else.) option READ_OPT_PLTE requires READ_ANCILLARY_CHUNKS # Unknown chunk handling diff --git a/scripts/pnglibconf.h.prebuilt b/scripts/pnglibconf.h.prebuilt index 5a3fed644..b524a76f6 100644 --- a/scripts/pnglibconf.h.prebuilt +++ b/scripts/pnglibconf.h.prebuilt @@ -27,7 +27,6 @@ #define PNG_CONSOLE_IO_SUPPORTED #define PNG_CONVERT_tIME_SUPPORTED #define PNG_EASY_ACCESS_SUPPORTED -/*#undef PNG_ERROR_NUMBERS_SUPPORTED*/ #define PNG_ERROR_TEXT_SUPPORTED #define PNG_FIXED_POINT_SUPPORTED #define PNG_FLOATING_ARITHMETIC_SUPPORTED @@ -103,7 +102,6 @@ #define PNG_SELECT_FILTER_SUPPORTED #define PNG_SEQUENTIAL_READ_SUPPORTED #define PNG_SETJMP_SUPPORTED -#define PNG_SETTING_SUPPORTED #define PNG_SET_OPTION_SUPPORTED #define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED #define PNG_SET_USER_LIMITS_SUPPORTED @@ -192,6 +190,7 @@ /* settings */ #define PNG_ABORT { (abort()); } #define PNG_API_RULE 0 +#define PNG_DEFAULT_COMPRESSION_LEVEL PNG_COMPRESSION_MEDIUM #define PNG_DEFAULT_GAMMA_ACCURACY 665 #define PNG_DEFAULT_READ_MACROS 1 #define PNG_GAMMA_THRESHOLD_FIXED 153 @@ -201,8 +200,6 @@ #define PNG_QUANTIZE_BLUE_BITS 5 #define PNG_QUANTIZE_GREEN_BITS 5 #define PNG_QUANTIZE_RED_BITS 5 -#define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1) -#define PNG_TEXT_Z_DEFAULT_STRATEGY 0 #define PNG_USER_CHUNK_CACHE_MAX 1000 #define PNG_USER_CHUNK_MALLOC_MAX 8000000 #define PNG_USER_HEIGHT_MAX 1000000 @@ -210,9 +207,6 @@ #define PNG_ZBUF_SIZE 4096 #define PNG_ZLIB_HEADER #define PNG_ZLIB_VERNUM 0 -#define PNG_Z_DEFAULT_COMPRESSION (-1) -#define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0 -#define PNG_Z_DEFAULT_STRATEGY 0 #define PNG_sCAL_PRECISION 5 #define PNG_sRGB_PROFILE_CHECKS 2 /* end of settings */ diff --git a/scripts/symbols.def b/scripts/symbols.def index 9b548bc42..1908e9406 100644 --- a/scripts/symbols.def +++ b/scripts/symbols.def @@ -53,7 +53,6 @@ EXPORTS png_set_strip_16 @48 png_set_quantize @49 png_set_gamma @50 - png_set_flush @51 png_write_flush @52 png_start_read_image @53 png_read_update_info @54 @@ -68,14 +67,6 @@ EXPORTS png_destroy_info_struct @63 png_destroy_read_struct @64 png_destroy_write_struct @65 - png_set_crc_action @66 - png_set_filter @67 - png_set_filter_heuristics @68 - png_set_compression_level @69 - png_set_compression_mem_level @70 - png_set_compression_strategy @71 - png_set_compression_window_bits @72 - png_set_compression_method @73 png_init_io @74 png_set_error_fn @75 png_get_error_ptr @76 @@ -108,7 +99,6 @@ EXPORTS png_chunk_warning @106 png_benign_error @107 png_chunk_benign_error @108 - png_set_benign_errors @109 png_get_valid @110 png_get_rowbytes @111 png_get_rows @112 @@ -184,7 +174,6 @@ EXPORTS png_get_header_version @182 png_get_libpng_ver @183 png_permit_mng_features @184 - png_set_strip_error_numbers @185 png_set_user_limits @186 png_get_user_width_max @187 png_get_user_height_max @188 @@ -206,7 +195,6 @@ EXPORTS png_save_uint_32 @205 png_save_uint_16 @207 png_set_gamma_fixed @208 - png_set_filter_heuristics_fixed @209 png_get_pixel_aspect_ratio_fixed @210 png_get_x_offset_inches_fixed @211 png_get_y_offset_inches_fixed @212 @@ -219,11 +207,6 @@ EXPORTS png_process_data_pause @219 png_process_data_skip @220 png_set_expand_16 @221 - png_set_text_compression_level @222 - png_set_text_compression_mem_level @223 - png_set_text_compression_strategy @224 - png_set_text_compression_window_bits @225 - png_set_text_compression_method @226 png_set_alpha_mode @227 png_set_alpha_mode_fixed @228 png_set_scale_16 @229 @@ -239,9 +222,7 @@ EXPORTS png_image_write_to_file @239 png_image_write_to_stdio @240 png_convert_to_rfc1123_buffer @241 - png_set_check_for_invalid_index @242 png_get_palette_max @243 - png_set_option @244 png_image_write_to_memory @245 png_memory_format @246 png_memory_channel_depth @247