diff --git a/contrib/libtests/pngstest.c b/contrib/libtests/pngstest.c index 8f27ac81d..d70871b28 100644 --- a/contrib/libtests/pngstest.c +++ b/contrib/libtests/pngstest.c @@ -307,7 +307,7 @@ compare_16bit(int v1, int v2, int error_limit, int multiple_algorithms) } #endif /* unused */ -#define READ_FILE 1 /* else memory */ +#define USE_FILE 1 /* else memory */ #define USE_STDIO 2 /* else use file name */ #define STRICT 4 /* fail on warnings too */ #define VERBOSE 8 @@ -320,7 +320,7 @@ compare_16bit(int v1, int v2, int error_limit, int multiple_algorithms) static void print_opts(png_uint_32 opts) { - if (opts & READ_FILE) + if (opts & USE_FILE) printf(" --file"); if (opts & USE_STDIO) printf(" --stdio"); @@ -3008,14 +3008,14 @@ read_file(Image *image, png_uint_32 format, png_const_colorp background) static int read_one_file(Image *image) { - if (!(image->opts & READ_FILE) || (image->opts & USE_STDIO)) + if (!(image->opts & USE_FILE) || (image->opts & USE_STDIO)) { /* memory or stdio. */ FILE *f = fopen(image->file_name, "rb"); if (f != NULL) { - if (image->opts & READ_FILE) + if (image->opts & USE_FILE) image->input_file = f; else /* memory */ @@ -3096,6 +3096,7 @@ write_one_file(Image *output, Image *image, int convert_to_8bit) if (image->opts & USE_STDIO) { +#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED #ifndef __COVERITY__ FILE *f = tmpfile(); #else @@ -3158,10 +3159,14 @@ write_one_file(Image *output, Image *image, int convert_to_8bit) else return logerror(image, "tmpfile", ": open: ", strerror(errno)); +#else /* SIMPLIFIED_WRITE_STDIO */ + return logerror(image, "tmpfile", ": open: unsupported", ""); +#endif /* SIMPLIFIED_WRITE_STDIO */ } - else + else if (image->opts & USE_FILE) { +#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED static int counter = 0; char name[32]; @@ -3181,6 +3186,48 @@ write_one_file(Image *output, Image *image, int convert_to_8bit) else return logerror(image, name, ": write failed", ""); +#else /* SIMPLIFIED_WRITE_STDIO */ + return logerror(image, "stdio", ": open: unsupported", ""); +#endif /* SIMPLIFIED_WRITE_STDIO */ + } + + else /* use memory */ + { + png_alloc_size_t size; + + if (png_image_write_get_memory_size(image->image, size, convert_to_8bit, + image->buffer+16, (png_int_32)image->stride, image->colormap)) + { + /* This is non-fatal: */ + if (size > PNG_IMAGE_PNG_SIZE_MAX(image->image)) + logerror(image, "memory", ": PNG_IMAGE_SIZE_MAX wrong", ""); + + initimage(output, image->opts, "memory", image->stride_extra); + output->input_memory = malloc(size); + + if (output->input_memory != NULL) + { + output->input_memory_size = size; + + if (png_image_write_to_memory(&image->image, output->input_memory, + &output->input_memory_size, convert_to_8bit, image->buffer+16, + (png_int_32)image->stride, image->colormap)) + { + /* This is also non-fatal (maybe): */ + if (size != output->input_memory_size) + logerror(image, "memory", ": memory size wrong", ""); + } + + else + return logerror(image, "memory", ": write failed", ""); + } + + else + return logerror(image, "memory", ": out of memory", ""); + } + + else + return logerror(image, "memory", ": get size:", ""); } /* 'output' has an initialized temporary image, read this back in and compare @@ -3421,12 +3468,12 @@ main(int argc, char **argv) } else if (strcmp(arg, "--file") == 0) # ifdef PNG_STDIO_SUPPORTED - opts |= READ_FILE; + opts |= USE_FILE; # else return 77; /* skipped: no support */ # endif else if (strcmp(arg, "--memory") == 0) - opts &= ~READ_FILE; + opts &= ~USE_FILE; else if (strcmp(arg, "--stdio") == 0) # ifdef PNG_STDIO_SUPPORTED opts |= USE_STDIO; diff --git a/png.h b/png.h index d24cf3aba..62aaeb038 100644 --- a/png.h +++ b/png.h @@ -2889,12 +2889,19 @@ typedef struct * is the minimum 'row stride', the minimum count of components between each * row. For a color-mapped image this is the minimum number of bytes in a * row. + * + * WARNING: this macro overflows for some images with more than one component + * and very large image widths. libpng will refuse to process an image where + * this macro would overflow. */ #define PNG_IMAGE_BUFFER_SIZE(image, row_stride)\ (PNG_IMAGE_PIXEL_COMPONENT_SIZE((image).format)*(image).height*(row_stride)) /* Return the size, in bytes, of an image buffer given a png_image and a row * stride - the number of components to leave space for in each row. + * + * WARNING: this macro overflows a 32-bit integer for some large PNG images, + * libpng will refuse to process an image where such an overflow would occur. */ #define PNG_IMAGE_SIZE(image)\ @@ -3015,7 +3022,6 @@ PNG_EXPORT(238, void, png_image_free, (png_imagep image)); #endif /* SIMPLIFIED_READ */ #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED -#ifdef PNG_STDIO_SUPPORTED /* WRITE APIS * ---------- * For write you must initialize a png_image structure to describe the image to @@ -3032,6 +3038,7 @@ PNG_EXPORT(238, void, png_image_free, (png_imagep image)); * values do not correspond to the colors in sRGB. * colormap_entries: set to the number of entries in the color-map (0 to 256) */ +#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image, const char *file, int convert_to_8bit, const void *buffer, png_int_32 row_stride, const void *colormap)); @@ -3041,8 +3048,9 @@ PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file, int convert_to_8_bit, const void *buffer, png_int_32 row_stride, const void *colormap)); /* Write the image to the given (FILE*). */ +#endif /* SIMPLIFIED_WRITE_STDIO */ -/* With both write APIs if image is in one of the linear formats with 16-bit +/* With all write APIs if image is in one of the linear formats with 16-bit * data then setting convert_to_8_bit will cause the output to be an 8-bit PNG * gamma encoded according to the sRGB specification, otherwise a 16-bit linear * encoded PNG file is written. @@ -3054,13 +3062,102 @@ PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file, * * With all APIs row_stride is handled as in the read APIs - it is the spacing * from one row to the next in component sized units (1 or 2 bytes) and if - * negative indicates a bottom-up row layout in the buffer. If row_stride is zero, - * libpng will calculate it for you from the image width and number of channels. + * negative indicates a bottom-up row layout in the buffer. If row_stride is + * zero, libpng will calculate it for you from the image width and number of + * channels. * - * Note that the write API does not support interlacing, sub-8-bit pixels, indexed - * PNG (color_type 3) or most ancillary chunks. + * Note that the write API does not support interlacing, sub-8-bit pixels or + * st ancillary chunks. If you need to write text chunks (e.g. for copyright + * notices) you need to use one of the other APIs. */ -#endif /* STDIO */ + +PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory, + png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8_bit, + const void *buffer, png_int_32 row_stride, const void *colormap)); + /* Write the image to the given memory buffer. The function both writes the + * whole PNG data stream to *memory and updates *memory_bytes with the count + * of bytes written. + * + * 'memory' may be NULL. In this case *memory_bytes is not read however on + * success the number of bytes which would have been written will still be + * stored in *memory_bytes. On failure *memory_bytes will contain 0. + * + * If 'memory' is not NULL it must point to memory[*memory_bytes] of + * writeable memory. + * + * If the function returns success memory[*memory_bytes] (if 'memory' is not + * NULL) contains the written PNG data. *memory_bytes will always be less + * than or equal to the original value. + * + * If the function returns false and *memory_bytes was not changed an error + * occured during write. If *memory_bytes was changed, or is not 0 if + * 'memory' was NULL, the write would have succeeded but for the memory + * buffer being too small. *memory_bytes contains the required number of + * bytes and will be bigger that the original value. + */ + +#define png_image_write_get_memory_size(image, size, convert_to_8_bit, buffer,\ + row_stride, colormap)\ + png_image_write_to_memory(&(image), 0, &(size), convert_to_8_bit, buffer,\ + row_stride, colormap) + /* Return the amount of memory in 'size' required to compress this image. + * The png_image structure 'image' must be filled in as in the above + * function and must not be changed before the actual write call, the buffer + * and all other parameters must also be indentical to that in the final + * write call. The 'size' variable need not be initialized. + * + * NOTE: the macro returns true/false, if false is returned 'size' will be + * set to zero and the write failed and probably will fail if tried again. + */ + +/* You can pre-allocate the buffer by making sure it is of sufficient size + * regardless of the amount of compression achieved. The buffer size will + * always be bigger than the original image and it will never be filled. The + * following macros are provided to assist in allocating the buffer. + */ +#define PNG_IMAGE_DATA_SIZE(image) (PNG_IMAGE_SIZE(image)+(image).height) + /* The number of uncompressed bytes in the PNG byte encoding of the image; + * uncompressing the PNG IDAT data will give this number of bytes. + * + * NOTE: while PNG_IMAGE_SIZE cannot overflow for an image in memory this + * macro can because of the extra bytes used in the PNG byte encoding. You + * need to avoid this macro if your image size approaches 2^30 in width or + * height. The same goes for the remainder of these macros; they all produce + * bigger numbers than the actual in-memory image size. + */ +#ifndef PNG_ZLIB_MAX_SIZE +# define PNG_ZLIB_MAX_SIZE(b) ((b)+(((b)+7U)>>3)+(((b)+63U)>>6)+11U) + /* An upper bound on the number of compressed bytes given 'b' uncompressed + * bytes. This is based on deflateBounds() in zlib; different + * implementations of zlib compression may conceivable produce more data so + * if your zlib implementation is not zlib itself redefine this macro + * appropriately. + */ +#endif + +#define PNG_IMAGE_COMPRESSED_SIZE_MAX(image)\ + PNG_ZLIB_MAX_SIZE((png_alloc_size_t)PNG_IMAGE_DATA_SIZE(image)) + /* An upper bound on the size of the data in the PNG IDAT chunks. */ + +#define PNG_IMAGE_PNG_SIZE_MAX_(image, image_size)\ + ((8U/*sig*/+25U/*IHDR*/+16U/*gAMA*/+44U/*cHRM*/+12U/*IEND*/+\ + (((image).format&PNG_FORMAT_FLAG_COLORMAP)?/*colormap: PLTE, tRNS*/\ + 12U+PNG_IMAGE_COLORMAP_SIZE(image)/*PLTE+tRNS data*/+\ + (((image).format&PNG_FORMAT_FLAG_ALPHA)?12U/*tRNS*/:0U):0U)+\ + 12U)+(12U*((image_size)/PNG_ZBUF_SIZE))/*IDAT*/+(image_size)) + /* A helper for the following macro; if your compiler cannot handle the + * following macro use this one with the result of + * PNG_IMAGE_COMPRESSED_SIZE_MAX(image) as the second argument (most + * compilers should handle this just fine.) + */ + +#define PNG_IMAGE_PNG_SIZE_MAX(image)\ + PNG_IMAGE_PNG_SIZE_MAX_(image, PNG_IMAGE_COMPRESSED_SIZE_MAX(image)) + /* An upper bound on the total length of the PNG data stream for 'image'. + * The result is of type png_alloc_size_t, on 32-bit systems this may + * overflow even though PNG_IMAGE_DATA_SIZE does not overflow; the write will + * run out of buffer space but return a corrected size which should work. + */ #endif /* SIMPLIFIED_WRITE */ /******************************************************************************* * END OF SIMPLIFIED API @@ -3118,7 +3215,7 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option, * one to use is one more than this.) */ #ifdef PNG_EXPORT_LAST_ORDINAL - PNG_EXPORT_LAST_ORDINAL(244); + PNG_EXPORT_LAST_ORDINAL(245); #endif #ifdef __cplusplus diff --git a/pngread.c b/pngread.c index dca3d7d53..614fcd19d 100644 --- a/pngread.c +++ b/pngread.c @@ -4071,58 +4071,84 @@ png_image_finish_read(png_imagep image, png_const_colorp background, { if (image != NULL && image->version == PNG_IMAGE_VERSION) { - png_uint_32 check; + /* Check for row_stride overflow. This check is not performed on the + * original PNG format because it may not occur in the output PNG format + * and libpng deals with the issues of reading the original. + */ + const unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format); - if (row_stride == 0) - row_stride = PNG_IMAGE_ROW_STRIDE(*image); - - if (row_stride < 0) - check = -row_stride; - - else - check = row_stride; - - if (image->opaque != NULL && buffer != NULL && - check >= PNG_IMAGE_ROW_STRIDE(*image)) + if (image->width <= 0x7FFFFFFFU/channels) /* no overflow */ { - if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 || - (image->colormap_entries > 0 && colormap != NULL)) + png_uint_32 check; + const png_uint_32 png_row_stride = image->width * channels; + + if (row_stride == 0) + row_stride = (png_int_32)/*SAFE*/png_row_stride; + + if (row_stride < 0) + check = -row_stride; + + else + check = row_stride; + + if (image->opaque != NULL && buffer != NULL && check >= png_row_stride) { - int result; - png_image_read_control display; - - memset(&display, 0, (sizeof display)); - display.image = image; - display.buffer = buffer; - display.row_stride = row_stride; - display.colormap = colormap; - display.background = background; - display.local_row = NULL; - - /* Choose the correct 'end' routine; for the color-map case all the - * setup has already been done. + /* Now check for overflow of the image buffer calculation; this + * limits the whole image size to 32 bits for API compatibility with + * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro. */ - if ((image->format & PNG_FORMAT_FLAG_COLORMAP) != 0) - result = - png_safe_execute(image, png_image_read_colormap, &display) && - png_safe_execute(image, png_image_read_colormapped, &display); + if (image->height <= 0xFFFFFFFF/png_row_stride) + { + if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 || + (image->colormap_entries > 0 && colormap != NULL)) + { + int result; + png_image_read_control display; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.background = background; + display.local_row = NULL; + + /* Choose the correct 'end' routine; for the color-map case + * all the setup has already been done. + */ + if ((image->format & PNG_FORMAT_FLAG_COLORMAP) != 0) + result = png_safe_execute(image, + png_image_read_colormap, &display) && + png_safe_execute(image, + png_image_read_colormapped, &display); + + else + result = + png_safe_execute(image, + png_image_read_direct, &display); + + png_image_free(image); + return result; + } + + else + return png_image_error(image, + "png_image_finish_read[color-map]: no color-map"); + } else - result = - png_safe_execute(image, png_image_read_direct, &display); - - png_image_free(image); - return result; + return png_image_error(image, + "png_image_finish_read: image too large"); } else return png_image_error(image, - "png_image_finish_read[color-map]: no color-map"); + "png_image_finish_read: invalid argument"); } else return png_image_error(image, - "png_image_finish_read: invalid argument"); + "png_image_finish_read: row_stride too large"); } else if (image != NULL) diff --git a/pngwrite.c b/pngwrite.c index f843796b8..181a89943 100644 --- a/pngwrite.c +++ b/pngwrite.c @@ -12,9 +12,9 @@ */ #include "pngpriv.h" -#if defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) +#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED # include -#endif +#endif /* SIMPLIFIED_WRITE_STDIO */ #ifdef PNG_WRITE_SUPPORTED @@ -1452,7 +1452,6 @@ png_write_png(png_structrp png_ptr, png_inforp info_ptr, #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED -# ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */ /* Initialize the write structure - general purpose utility. */ static int png_image_write_init(png_imagep image) @@ -1504,6 +1503,10 @@ typedef struct png_const_voidp first_row; ptrdiff_t row_bytes; png_voidp local_row; + /* Byte count for memory writing */ + png_bytep memory; + png_alloc_size_t memory_bytes; /* not used for STDIO */ + png_alloc_size_t output_bytes; /* running total */ } png_image_write_control; /* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to @@ -1931,9 +1934,43 @@ png_image_write_main(png_voidp argument) png_set_benign_errors(png_ptr, 0/*error*/); # endif - /* Default the 'row_stride' parameter if required. */ - if (display->row_stride == 0) - display->row_stride = PNG_IMAGE_ROW_STRIDE(*image); + /* Default the 'row_stride' parameter if required, also check the row stride + * and total image size to ensure that they are within the system limits. + */ + { + const unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format); + + if (image->width <= 0x7FFFFFFFU/channels) /* no overflow */ + { + png_uint_32 check; + const png_uint_32 png_row_stride = image->width * channels; + + if (display->row_stride == 0) + display->row_stride = (png_int_32)/*SAFE*/png_row_stride; + + if (display->row_stride < 0) + check = -display->row_stride; + + else + check = display->row_stride; + + if (check >= png_row_stride) + { + /* Now check for overflow of the image buffer calculation; this + * limits the whole image size to 32 bits for API compatibility with + * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro. + */ + if (image->height > 0xFFFFFFFF/png_row_stride) + png_error(image->opaque->png_ptr, "memory image too large"); + } + + else + png_error(image->opaque->png_ptr, "supplied row stride too small"); + } + + else + png_error(image->opaque->png_ptr, "image row stride too large"); + } /* Set the required transforms then write the rows in the correct order. */ if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0) @@ -2110,6 +2147,122 @@ png_image_write_main(png_voidp argument) return 1; } + +static void (PNGCBAPI +image_memory_write)(png_structp png_ptr, png_bytep/*const*/ data, + png_size_t size) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + png_ptr->io_ptr/*backdoor: png_get_io_ptr(png_ptr)*/); + const png_alloc_size_t ob = display->output_bytes; + + /* Check for overflow; this should never happen: */ + if (size <= ((png_alloc_size_t)-1) - ob) + { + /* I don't think libpng ever does this, but just in case: */ + if (size > 0) + { + if (display->memory_bytes >= ob+size) /* writing */ + memcpy(display->memory+ob, data, size); + + /* Always update the size: */ + display->output_bytes = ob+size; + } + } + + else + png_error(png_ptr, "png_image_write_to_memory: PNG too big"); +} + +static void (PNGCBAPI +image_memory_flush)(png_structp png_ptr) +{ + PNG_UNUSED(png_ptr) +} + +static int +png_image_write_memory(png_voidp argument) +{ + png_image_write_control *display = png_voidcast(png_image_write_control*, + argument); + + /* The rest of the memory-specific init and write_main in an error protected + * environment. This case needs to use callbacks for the write operations + * since libpng has no built in support for writing to memory. + */ + png_set_write_fn(display->image->opaque->png_ptr, display/*io_ptr*/, + image_memory_write, image_memory_flush); + + return png_image_write_main(display); +} + +int PNGAPI +png_image_write_to_memory(png_imagep image, void *memory, + png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8bit, + const void *buffer, png_int_32 row_stride, const void *colormap) +{ + /* Write the image to the given buffer, or count the bytes if it is NULL */ + if (image != NULL && image->version == PNG_IMAGE_VERSION) + { + if (memory_bytes != NULL && buffer != NULL) + { + /* This is to give the caller an easier error detection in the NULL + * case and guard against uninitialized variable problems: + */ + if (memory == NULL) + *memory_bytes = 0; + + if (png_image_write_init(image) != 0) + { + png_image_write_control display; + int result; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.convert_to_8bit = convert_to_8bit; + display.memory = png_voidcast(png_bytep, memory); + display.memory_bytes = *memory_bytes; + display.output_bytes = 0; + + result = png_safe_execute(image, png_image_write_memory, &display); + png_image_free(image); + + /* write_memory returns true even if we ran out of buffer. */ + if (result) + { + /* On out-of-buffer this function returns '0' but still updates + * memory_bytes: + */ + if (memory != NULL && display.output_bytes > *memory_bytes) + result = 0; + + *memory_bytes = display.output_bytes; + } + + return result; + } + + else + return 0; + } + + else + return png_image_error(image, + "png_image_write_to_memory: invalid argument"); + } + + else if (image != NULL) + return png_image_error(image, + "png_image_write_to_memory: incorrect PNG_IMAGE_VERSION"); + + else + return 0; +} + +#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED int PNGAPI png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, const void *buffer, png_int_32 row_stride, const void *colormap) @@ -2117,7 +2270,7 @@ png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, /* Write the image to the given (FILE*). */ if (image != NULL && image->version == PNG_IMAGE_VERSION) { - if (file != NULL) + if (file != NULL && buffer != NULL) { if (png_image_write_init(image) != 0) { @@ -2167,7 +2320,7 @@ png_image_write_to_file(png_imagep image, const char *file_name, /* Write the image to the named file. */ if (image != NULL && image->version == PNG_IMAGE_VERSION) { - if (file_name != NULL) + if (file_name != NULL && buffer != NULL) { FILE *fp = fopen(file_name, "wb"); @@ -2225,6 +2378,6 @@ png_image_write_to_file(png_imagep image, const char *file_name, else return 0; } -# endif /* STDIO */ +#endif /* SIMPLIFIED_WRITE_STDIO */ #endif /* SIMPLIFIED_WRITE */ #endif /* WRITE */ diff --git a/scripts/pnglibconf.dfa b/scripts/pnglibconf.dfa index adffd30e0..2c936c22f 100644 --- a/scripts/pnglibconf.dfa +++ b/scripts/pnglibconf.dfa @@ -873,9 +873,12 @@ option SIMPLIFIED_READ_BGR enables FORMAT_BGR, # Write: option SIMPLIFIED_WRITE, - requires WRITE STDIO, SETJMP, WRITE_SWAP, WRITE_PACK, + requires WRITE, SETJMP, WRITE_SWAP, WRITE_PACK, WRITE_tRNS, WRITE_gAMA, WRITE_sRGB, WRITE_cHRM +# 1.6.22: allow simplified write without stdio support: +option SIMPLIFIED_WRITE_STDIO requires SIMPLIFIED_WRITE STDIO + option SIMPLIFIED_WRITE_AFIRST enables FORMAT_AFIRST, requires SIMPLIFIED_WRITE WRITE_SWAP_ALPHA diff --git a/scripts/pnglibconf.h.prebuilt b/scripts/pnglibconf.h.prebuilt index a6e0a0d46..26f086bfd 100644 --- a/scripts/pnglibconf.h.prebuilt +++ b/scripts/pnglibconf.h.prebuilt @@ -109,6 +109,7 @@ #define PNG_SIMPLIFIED_READ_SUPPORTED #define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED #define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED +#define PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED #define PNG_SIMPLIFIED_WRITE_SUPPORTED #define PNG_STDIO_SUPPORTED #define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED diff --git a/scripts/symbols.def b/scripts/symbols.def index 43a457f8e..ecdec3be4 100644 --- a/scripts/symbols.def +++ b/scripts/symbols.def @@ -249,3 +249,4 @@ EXPORTS png_set_check_for_invalid_index @242 png_get_palette_max @243 png_set_option @244 + png_image_write_to_memory @245