提交 94f4e972 编写于 作者: G Glenn Randers-Pehrson

Merge branch 'libpng16-simple-memory-II' of git://github.com/jbowler/libpng-1 into libpng16

...@@ -307,7 +307,7 @@ compare_16bit(int v1, int v2, int error_limit, int multiple_algorithms) ...@@ -307,7 +307,7 @@ compare_16bit(int v1, int v2, int error_limit, int multiple_algorithms)
} }
#endif /* unused */ #endif /* unused */
#define READ_FILE 1 /* else memory */ #define USE_FILE 1 /* else memory */
#define USE_STDIO 2 /* else use file name */ #define USE_STDIO 2 /* else use file name */
#define STRICT 4 /* fail on warnings too */ #define STRICT 4 /* fail on warnings too */
#define VERBOSE 8 #define VERBOSE 8
...@@ -320,7 +320,7 @@ compare_16bit(int v1, int v2, int error_limit, int multiple_algorithms) ...@@ -320,7 +320,7 @@ compare_16bit(int v1, int v2, int error_limit, int multiple_algorithms)
static void static void
print_opts(png_uint_32 opts) print_opts(png_uint_32 opts)
{ {
if (opts & READ_FILE) if (opts & USE_FILE)
printf(" --file"); printf(" --file");
if (opts & USE_STDIO) if (opts & USE_STDIO)
printf(" --stdio"); printf(" --stdio");
...@@ -3008,14 +3008,14 @@ read_file(Image *image, png_uint_32 format, png_const_colorp background) ...@@ -3008,14 +3008,14 @@ read_file(Image *image, png_uint_32 format, png_const_colorp background)
static int static int
read_one_file(Image *image) 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. */ /* memory or stdio. */
FILE *f = fopen(image->file_name, "rb"); FILE *f = fopen(image->file_name, "rb");
if (f != NULL) if (f != NULL)
{ {
if (image->opts & READ_FILE) if (image->opts & USE_FILE)
image->input_file = f; image->input_file = f;
else /* memory */ else /* memory */
...@@ -3096,6 +3096,7 @@ write_one_file(Image *output, Image *image, int convert_to_8bit) ...@@ -3096,6 +3096,7 @@ write_one_file(Image *output, Image *image, int convert_to_8bit)
if (image->opts & USE_STDIO) if (image->opts & USE_STDIO)
{ {
#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
#ifndef __COVERITY__ #ifndef __COVERITY__
FILE *f = tmpfile(); FILE *f = tmpfile();
#else #else
...@@ -3158,10 +3159,14 @@ write_one_file(Image *output, Image *image, int convert_to_8bit) ...@@ -3158,10 +3159,14 @@ write_one_file(Image *output, Image *image, int convert_to_8bit)
else else
return logerror(image, "tmpfile", ": open: ", strerror(errno)); 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; static int counter = 0;
char name[32]; char name[32];
...@@ -3181,6 +3186,48 @@ write_one_file(Image *output, Image *image, int convert_to_8bit) ...@@ -3181,6 +3186,48 @@ write_one_file(Image *output, Image *image, int convert_to_8bit)
else else
return logerror(image, name, ": write failed", ""); 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 /* 'output' has an initialized temporary image, read this back in and compare
...@@ -3421,12 +3468,12 @@ main(int argc, char **argv) ...@@ -3421,12 +3468,12 @@ main(int argc, char **argv)
} }
else if (strcmp(arg, "--file") == 0) else if (strcmp(arg, "--file") == 0)
# ifdef PNG_STDIO_SUPPORTED # ifdef PNG_STDIO_SUPPORTED
opts |= READ_FILE; opts |= USE_FILE;
# else # else
return 77; /* skipped: no support */ return 77; /* skipped: no support */
# endif # endif
else if (strcmp(arg, "--memory") == 0) else if (strcmp(arg, "--memory") == 0)
opts &= ~READ_FILE; opts &= ~USE_FILE;
else if (strcmp(arg, "--stdio") == 0) else if (strcmp(arg, "--stdio") == 0)
# ifdef PNG_STDIO_SUPPORTED # ifdef PNG_STDIO_SUPPORTED
opts |= USE_STDIO; opts |= USE_STDIO;
......
...@@ -2889,12 +2889,19 @@ typedef struct ...@@ -2889,12 +2889,19 @@ typedef struct
* is the minimum 'row stride', the minimum count of components between each * 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. For a color-mapped image this is the minimum number of bytes in a
* row. * 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)\ #define PNG_IMAGE_BUFFER_SIZE(image, row_stride)\
(PNG_IMAGE_PIXEL_COMPONENT_SIZE((image).format)*(image).height*(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 /* 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. * 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)\ #define PNG_IMAGE_SIZE(image)\
...@@ -3015,7 +3022,6 @@ PNG_EXPORT(238, void, png_image_free, (png_imagep image)); ...@@ -3015,7 +3022,6 @@ PNG_EXPORT(238, void, png_image_free, (png_imagep image));
#endif /* SIMPLIFIED_READ */ #endif /* SIMPLIFIED_READ */
#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
#ifdef PNG_STDIO_SUPPORTED
/* WRITE APIS /* WRITE APIS
* ---------- * ----------
* For write you must initialize a png_image structure to describe the image to * 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)); ...@@ -3032,6 +3038,7 @@ PNG_EXPORT(238, void, png_image_free, (png_imagep image));
* values do not correspond to the colors in sRGB. * values do not correspond to the colors in sRGB.
* colormap_entries: set to the number of entries in the color-map (0 to 256) * 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, PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image,
const char *file, int convert_to_8bit, const void *buffer, const char *file, int convert_to_8bit, const void *buffer,
png_int_32 row_stride, const void *colormap)); 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, ...@@ -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, int convert_to_8_bit, const void *buffer, png_int_32 row_stride,
const void *colormap)); const void *colormap));
/* Write the image to the given (FILE*). */ /* 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 * 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 * gamma encoded according to the sRGB specification, otherwise a 16-bit linear
* encoded PNG file is written. * encoded PNG file is written.
...@@ -3054,13 +3062,102 @@ PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file, ...@@ -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 * 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 * 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, * negative indicates a bottom-up row layout in the buffer. If row_stride is
* libpng will calculate it for you from the image width and number of channels. * 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.
*/
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 /* STDIO */
#endif /* SIMPLIFIED_WRITE */ #endif /* SIMPLIFIED_WRITE */
/******************************************************************************* /*******************************************************************************
* END OF SIMPLIFIED API * END OF SIMPLIFIED API
...@@ -3118,7 +3215,7 @@ PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option, ...@@ -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.) * one to use is one more than this.)
*/ */
#ifdef PNG_EXPORT_LAST_ORDINAL #ifdef PNG_EXPORT_LAST_ORDINAL
PNG_EXPORT_LAST_ORDINAL(244); PNG_EXPORT_LAST_ORDINAL(245);
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
......
...@@ -4070,11 +4070,20 @@ png_image_finish_read(png_imagep image, png_const_colorp background, ...@@ -4070,11 +4070,20 @@ png_image_finish_read(png_imagep image, png_const_colorp background,
void *buffer, png_int_32 row_stride, void *colormap) void *buffer, png_int_32 row_stride, void *colormap)
{ {
if (image != NULL && image->version == PNG_IMAGE_VERSION) if (image != NULL && image->version == PNG_IMAGE_VERSION)
{
/* 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 (image->width <= 0x7FFFFFFFU/channels) /* no overflow */
{ {
png_uint_32 check; png_uint_32 check;
const png_uint_32 png_row_stride = image->width * channels;
if (row_stride == 0) if (row_stride == 0)
row_stride = PNG_IMAGE_ROW_STRIDE(*image); row_stride = (png_int_32)/*SAFE*/png_row_stride;
if (row_stride < 0) if (row_stride < 0)
check = -row_stride; check = -row_stride;
...@@ -4082,8 +4091,13 @@ png_image_finish_read(png_imagep image, png_const_colorp background, ...@@ -4082,8 +4091,13 @@ png_image_finish_read(png_imagep image, png_const_colorp background,
else else
check = row_stride; check = row_stride;
if (image->opaque != NULL && buffer != NULL && if (image->opaque != NULL && buffer != NULL && check >= png_row_stride)
check >= PNG_IMAGE_ROW_STRIDE(*image)) {
/* 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)
{ {
if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 || if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 ||
(image->colormap_entries > 0 && colormap != NULL)) (image->colormap_entries > 0 && colormap != NULL))
...@@ -4099,17 +4113,19 @@ png_image_finish_read(png_imagep image, png_const_colorp background, ...@@ -4099,17 +4113,19 @@ png_image_finish_read(png_imagep image, png_const_colorp background,
display.background = background; display.background = background;
display.local_row = NULL; display.local_row = NULL;
/* Choose the correct 'end' routine; for the color-map case all the /* Choose the correct 'end' routine; for the color-map case
* setup has already been done. * all the setup has already been done.
*/ */
if ((image->format & PNG_FORMAT_FLAG_COLORMAP) != 0) if ((image->format & PNG_FORMAT_FLAG_COLORMAP) != 0)
result = result = png_safe_execute(image,
png_safe_execute(image, png_image_read_colormap, &display) && png_image_read_colormap, &display) &&
png_safe_execute(image, png_image_read_colormapped, &display); png_safe_execute(image,
png_image_read_colormapped, &display);
else else
result = result =
png_safe_execute(image, png_image_read_direct, &display); png_safe_execute(image,
png_image_read_direct, &display);
png_image_free(image); png_image_free(image);
return result; return result;
...@@ -4120,11 +4136,21 @@ png_image_finish_read(png_imagep image, png_const_colorp background, ...@@ -4120,11 +4136,21 @@ png_image_finish_read(png_imagep image, png_const_colorp background,
"png_image_finish_read[color-map]: no color-map"); "png_image_finish_read[color-map]: no color-map");
} }
else
return png_image_error(image,
"png_image_finish_read: image too large");
}
else else
return png_image_error(image, return png_image_error(image,
"png_image_finish_read: invalid argument"); "png_image_finish_read: invalid argument");
} }
else
return png_image_error(image,
"png_image_finish_read: row_stride too large");
}
else if (image != NULL) else if (image != NULL)
return png_image_error(image, return png_image_error(image,
"png_image_finish_read: damaged PNG_IMAGE_VERSION"); "png_image_finish_read: damaged PNG_IMAGE_VERSION");
......
...@@ -12,9 +12,9 @@ ...@@ -12,9 +12,9 @@
*/ */
#include "pngpriv.h" #include "pngpriv.h"
#if defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) #ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
# include <errno.h> # include <errno.h>
#endif #endif /* SIMPLIFIED_WRITE_STDIO */
#ifdef PNG_WRITE_SUPPORTED #ifdef PNG_WRITE_SUPPORTED
...@@ -1452,7 +1452,6 @@ png_write_png(png_structrp png_ptr, png_inforp info_ptr, ...@@ -1452,7 +1452,6 @@ png_write_png(png_structrp png_ptr, png_inforp info_ptr,
#ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED
# ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */
/* Initialize the write structure - general purpose utility. */ /* Initialize the write structure - general purpose utility. */
static int static int
png_image_write_init(png_imagep image) png_image_write_init(png_imagep image)
...@@ -1504,6 +1503,10 @@ typedef struct ...@@ -1504,6 +1503,10 @@ typedef struct
png_const_voidp first_row; png_const_voidp first_row;
ptrdiff_t row_bytes; ptrdiff_t row_bytes;
png_voidp local_row; 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; } png_image_write_control;
/* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to /* 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) ...@@ -1931,9 +1934,43 @@ png_image_write_main(png_voidp argument)
png_set_benign_errors(png_ptr, 0/*error*/); png_set_benign_errors(png_ptr, 0/*error*/);
# endif # endif
/* Default the 'row_stride' parameter if required. */ /* 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) if (display->row_stride == 0)
display->row_stride = PNG_IMAGE_ROW_STRIDE(*image); 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. */ /* Set the required transforms then write the rows in the correct order. */
if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0) if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0)
...@@ -2110,6 +2147,122 @@ png_image_write_main(png_voidp argument) ...@@ -2110,6 +2147,122 @@ png_image_write_main(png_voidp argument)
return 1; 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 int PNGAPI
png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, 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) 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, ...@@ -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*). */ /* Write the image to the given (FILE*). */
if (image != NULL && image->version == PNG_IMAGE_VERSION) if (image != NULL && image->version == PNG_IMAGE_VERSION)
{ {
if (file != NULL) if (file != NULL && buffer != NULL)
{ {
if (png_image_write_init(image) != 0) if (png_image_write_init(image) != 0)
{ {
...@@ -2167,7 +2320,7 @@ png_image_write_to_file(png_imagep image, const char *file_name, ...@@ -2167,7 +2320,7 @@ png_image_write_to_file(png_imagep image, const char *file_name,
/* Write the image to the named file. */ /* Write the image to the named file. */
if (image != NULL && image->version == PNG_IMAGE_VERSION) if (image != NULL && image->version == PNG_IMAGE_VERSION)
{ {
if (file_name != NULL) if (file_name != NULL && buffer != NULL)
{ {
FILE *fp = fopen(file_name, "wb"); FILE *fp = fopen(file_name, "wb");
...@@ -2225,6 +2378,6 @@ png_image_write_to_file(png_imagep image, const char *file_name, ...@@ -2225,6 +2378,6 @@ png_image_write_to_file(png_imagep image, const char *file_name,
else else
return 0; return 0;
} }
# endif /* STDIO */ #endif /* SIMPLIFIED_WRITE_STDIO */
#endif /* SIMPLIFIED_WRITE */ #endif /* SIMPLIFIED_WRITE */
#endif /* WRITE */ #endif /* WRITE */
...@@ -873,9 +873,12 @@ option SIMPLIFIED_READ_BGR enables FORMAT_BGR, ...@@ -873,9 +873,12 @@ option SIMPLIFIED_READ_BGR enables FORMAT_BGR,
# Write: # Write:
option SIMPLIFIED_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 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, option SIMPLIFIED_WRITE_AFIRST enables FORMAT_AFIRST,
requires SIMPLIFIED_WRITE WRITE_SWAP_ALPHA requires SIMPLIFIED_WRITE WRITE_SWAP_ALPHA
......
...@@ -109,6 +109,7 @@ ...@@ -109,6 +109,7 @@
#define PNG_SIMPLIFIED_READ_SUPPORTED #define PNG_SIMPLIFIED_READ_SUPPORTED
#define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED #define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED
#define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED #define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED
#define PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED
#define PNG_SIMPLIFIED_WRITE_SUPPORTED #define PNG_SIMPLIFIED_WRITE_SUPPORTED
#define PNG_STDIO_SUPPORTED #define PNG_STDIO_SUPPORTED
#define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED #define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
......
...@@ -249,3 +249,4 @@ EXPORTS ...@@ -249,3 +249,4 @@ EXPORTS
png_set_check_for_invalid_index @242 png_set_check_for_invalid_index @242
png_get_palette_max @243 png_get_palette_max @243
png_set_option @244 png_set_option @244
png_image_write_to_memory @245
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册