mirror of
https://git.code.sf.net/p/libpng/code.git
synced 2025-07-10 18:04:09 +02:00
Write code update
Implemented better defaulting of zlib settings based on image properties. Implemented pass-through of png_write_rows when the rows can be used directly (a common case) optimizing the handling of previous-row buffering. Removed the METHODICAL filter selection method and disabled the HEURISTIC one; the first was ridiculously slow (though useful for experiments) the second doesn't work. Filter selection is temporarily disabled (it defaults to the lowest numbered filter in the list; typically 'none'). New handling of compression settings (incomplete), new PNG compression level (not yet visible in an API). Back ported 'PNG_FAST_FILTERS' from 1.6 (in png.h). There are minimal API changes beyond removal of the selection options. Work is still to be done to investigate a filter selection mechanism that is at least as good as the previous one. Signed-off-by: John Bowler <jbowler@acm.org>
This commit is contained in:
parent
1fd42d849d
commit
cde9b583a8
@ -1609,10 +1609,10 @@ read_png(struct display *dp, const char *filename)
|
|||||||
png_alloc_size_t rb = png_get_rowbytes(dp->read_pp, dp->ip);
|
png_alloc_size_t rb = png_get_rowbytes(dp->read_pp, dp->ip);
|
||||||
|
|
||||||
/* The size calc can overflow. */
|
/* The size calc can overflow. */
|
||||||
if (MAX_SIZE/rb < dp->h)
|
if ((MAX_SIZE-dp->h)/rb < dp->h)
|
||||||
png_error(dp->read_pp, "image too large");
|
png_error(dp->read_pp, "image too large");
|
||||||
|
|
||||||
dp->size = rb * dp->h;
|
dp->size = rb * dp->h + dp->h/*filter byte*/;
|
||||||
}
|
}
|
||||||
|
|
||||||
display_clean_read(dp);
|
display_clean_read(dp);
|
||||||
@ -1826,18 +1826,21 @@ write_png(struct display *dp, const char *destname)
|
|||||||
static void
|
static void
|
||||||
set_windowBits_hi(struct display *dp)
|
set_windowBits_hi(struct display *dp)
|
||||||
{
|
{
|
||||||
/* windowBits is in the range 8..15, but it is said that setting '8'
|
/* windowBits is in the range 8..15 but zlib maps '8' to '9' so it is only
|
||||||
* prevents adequate search even if the image size is 256 bytes or less.
|
* worth using if the data size is 256 byte or less.
|
||||||
*/
|
*/
|
||||||
int wb = MAX_WBITS; /* for large images */
|
int wb = MAX_WBITS; /* for large images */
|
||||||
int i = VLSIZE(windowBits_IDAT);
|
int i = VLSIZE(windowBits_IDAT);
|
||||||
|
|
||||||
while (wb > 9 && dp->size <= 1U<<(wb-1)) --wb;
|
while (wb > 8 && dp->size <= 1U<<(wb-1)) --wb;
|
||||||
|
|
||||||
while (--i >= 0) if (VLNAME(windowBits_IDAT)[i].name == range_hi) break;
|
while (--i >= 0) if (VLNAME(windowBits_IDAT)[i].name == range_hi) break;
|
||||||
|
|
||||||
assert(i > 0); /* vl_windowBits_IDAT always has a RANGE() */
|
assert(i > 1); /* vl_windowBits_IDAT always has a RANGE() */
|
||||||
VLNAME(windowBits_IDAT)[i].value = wb;
|
VLNAME(windowBits_IDAT)[i].value = wb;
|
||||||
|
|
||||||
|
assert(VLNAME(windowBits_IDAT)[--i].name == range_lo);
|
||||||
|
VLNAME(windowBits_IDAT)[i].value = wb > 8 ? 9 : 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
43
png.h
43
png.h
@ -1690,25 +1690,14 @@ PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action,
|
|||||||
* ignored if SUB is set; this is because these filter pairs are equivalent
|
* ignored if SUB is set; this is because these filter pairs are equivalent
|
||||||
* when there is no previous row.
|
* when there is no previous row.
|
||||||
*
|
*
|
||||||
* 2) PNG_SELECT_FILTER_METHODICALLY_SUPPORTED:
|
* 2) PNG_SELECT_FILTER_SUPPORTED:
|
||||||
* If SELECT_FILTER_METHODICALLY is 'on' libpng tries all the filters in the
|
* libpng will buffer rows until enough data is available to perform a
|
||||||
* list and selects the one which gives the shortest compressed row, favoring
|
* reasonable filter selection heuristic then select filters for at least the
|
||||||
* earlier filters.
|
* first buffered row.
|
||||||
*
|
*
|
||||||
* 3) PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED:
|
* 3) !PNG_SELECT_FILTER_SUPPORTED:
|
||||||
* If SELECT_FILTER_HEURISTICALLY is 'on' libpng tests the start of each row
|
* libpng selects the first filter in the list (there is no warning that this
|
||||||
* (a few thousand bytes at most) to see which filter is likely to produce
|
* will happen - check the #defines if you need to know.)
|
||||||
* best compression.
|
|
||||||
*
|
|
||||||
* 4) If neither (2) nor (3) libpng selects the first filter in the list (there
|
|
||||||
* is no warning that this will happen - check the #defines if you need to
|
|
||||||
* know.)
|
|
||||||
*
|
|
||||||
* The seletion options are turned 'on' using png_set_option(method,
|
|
||||||
* PNG_OPTION_ON) and turned off with PNG_OPTION_OFF. If a selection method is
|
|
||||||
* turned off it will never be used, if neither option is turned on or off (i.e.
|
|
||||||
* if png_set_option is not called) the first supported option (2) or (3) will
|
|
||||||
* be used.
|
|
||||||
*
|
*
|
||||||
* If you intend to use 'previous row' filters in an image set either the UP or
|
* 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
|
* PAETH filter before the first call to png_write_row, depending on whether you
|
||||||
@ -1717,12 +1706,6 @@ PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action,
|
|||||||
* You can also select AVG on the first row; it uses half the value of the
|
* 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
|
* preceding byte as a predictor and is not likely to have very good
|
||||||
* performance.
|
* performance.
|
||||||
*
|
|
||||||
* The SELECT_FILTER_METHODICALLY option is slow and memory intensive, but it is
|
|
||||||
* almost certain to produce the smallest PNG file. Depending on the image data
|
|
||||||
* the HEURISTIC option may improve results significantly over the NONE filter
|
|
||||||
* and it has little overall effect on compression speed, however it can
|
|
||||||
* sometimes produce larger files than not using any filtering.
|
|
||||||
*/
|
*/
|
||||||
PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method,
|
PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method,
|
||||||
int filters));
|
int filters));
|
||||||
@ -1752,12 +1735,12 @@ PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method,
|
|||||||
#define PNG_FILTER_AVG PNG_FILTER_MASK(PNG_FILTER_VALUE_AVG)
|
#define PNG_FILTER_AVG PNG_FILTER_MASK(PNG_FILTER_VALUE_AVG)
|
||||||
#define PNG_FILTER_PAETH PNG_FILTER_MASK(PNG_FILTER_VALUE_PAETH)
|
#define PNG_FILTER_PAETH PNG_FILTER_MASK(PNG_FILTER_VALUE_PAETH)
|
||||||
|
|
||||||
/* Then two convenience values. PNG_NO_FILTERS is the same as
|
/* Then three convenience values. PNG_NO_FILTERS is the same as
|
||||||
* PNG_FILTER_VALUE_NONE, but this is harmless because they mean the same thing.
|
* PNG_FILTER_VALUE_NONE, but this is harmless because they mean the same thing.
|
||||||
*/
|
*/
|
||||||
#define PNG_NO_FILTERS 0x00
|
#define PNG_NO_FILTERS 0x00
|
||||||
#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \
|
#define PNG_FAST_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP)
|
||||||
PNG_FILTER_AVG | PNG_FILTER_PAETH)
|
#define PNG_ALL_FILTERS (PNG_FAST_FILTERS | PNG_FILTER_AVG | PNG_FILTER_PAETH)
|
||||||
|
|
||||||
#ifdef PNG_WRITE_SUPPORTED
|
#ifdef PNG_WRITE_SUPPORTED
|
||||||
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */
|
#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */
|
||||||
@ -3629,9 +3612,7 @@ PNG_EXPORT(245, int, png_image_write_to_memory, (png_imagep image, void *memory,
|
|||||||
#define PNG_EXTENSIONS 0 /* BOTH: enable or disable extensions */
|
#define PNG_EXTENSIONS 0 /* BOTH: enable or disable extensions */
|
||||||
#define PNG_MAXIMUM_INFLATE_WINDOW 2 /* SOFTWARE: force maximum window */
|
#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_SKIP_sRGB_CHECK_PROFILE 4 /* SOFTWARE: Check ICC profile for sRGB */
|
||||||
#define PNG_SELECT_FILTER_HEURISTICALLY 6 /* SOFTWARE: see png_set_filter */
|
#define PNG_OPTION_NEXT 6 /* Next option - numbers must be even */
|
||||||
#define PNG_SELECT_FILTER_METHODICALLY 8 /* SOFTWARE: see png_set_filter */
|
|
||||||
#define PNG_OPTION_NEXT 10 /* Next option - numbers must be even */
|
|
||||||
|
|
||||||
/* Return values: NOTE: there are four values and 'off' is *not* zero */
|
/* Return values: NOTE: there are four values and 'off' is *not* zero */
|
||||||
#define PNG_OPTION_UNSET 0 /* Unset - defaults to off */
|
#define PNG_OPTION_UNSET 0 /* Unset - defaults to off */
|
||||||
|
22
pngpriv.h
22
pngpriv.h
@ -1080,10 +1080,6 @@ PNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr,
|
|||||||
PNG_INTERNAL_FUNCTION(void,png_calculate_crc,(png_structrp png_ptr,
|
PNG_INTERNAL_FUNCTION(void,png_calculate_crc,(png_structrp png_ptr,
|
||||||
png_const_voidp ptr, png_size_t length),PNG_EMPTY);
|
png_const_voidp ptr, png_size_t length),PNG_EMPTY);
|
||||||
|
|
||||||
#ifdef PNG_WRITE_FLUSH_SUPPORTED
|
|
||||||
PNG_INTERNAL_FUNCTION(void,png_flush,(png_structrp png_ptr),PNG_EMPTY);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Write various chunks */
|
/* Write various chunks */
|
||||||
|
|
||||||
/* Write the IHDR chunk, and update the png_struct with the necessary
|
/* Write the IHDR chunk, and update the png_struct with the necessary
|
||||||
@ -1199,9 +1195,9 @@ PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr,
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef PNG_WRITE_SUPPORTED
|
#ifdef PNG_WRITE_SUPPORTED
|
||||||
/* Initialize the row compression mechanism. */
|
PNG_INTERNAL_FUNCTION(void,png_write_start_IDAT,(png_structrp png_ptr),
|
||||||
PNG_INTERNAL_FUNCTION(void, png_write_start_IDAT, (png_structp png_ptr),
|
PNG_EMPTY);
|
||||||
PNG_EMPTY);
|
/* Do any required initialization before IDAT or row processing starts. */
|
||||||
|
|
||||||
/* Choose the best filter to use and filter the row data then write it out. If
|
/* Choose the best filter to use and filter the row data then write it out. If
|
||||||
* WRITE_FILTERING is not supported this just writes the data out with a zero
|
* WRITE_FILTERING is not supported this just writes the data out with a zero
|
||||||
@ -1226,11 +1222,21 @@ enum
|
|||||||
# define PNG_IDAT_END(f) (((f) & ~png_pass_first_row) == \
|
# define PNG_IDAT_END(f) (((f) & ~png_pass_first_row) == \
|
||||||
(png_row_end+png_pass_last_row+png_pass_last))
|
(png_row_end+png_pass_last_row+png_pass_last))
|
||||||
};
|
};
|
||||||
PNG_INTERNAL_FUNCTION(void, png_write_filter_row, (png_structrp png_ptr,
|
PNG_INTERNAL_FUNCTION(void,png_write_png_data,(png_structrp png_ptr,
|
||||||
png_bytep prev_pixels, png_const_bytep unfiltered_row, png_uint_32 x,
|
png_bytep prev_pixels, png_const_bytep unfiltered_row, png_uint_32 x,
|
||||||
unsigned int width/*pixels*/, unsigned int row_info_flags),
|
unsigned int width/*pixels*/, unsigned int row_info_flags),
|
||||||
PNG_EMPTY);
|
PNG_EMPTY);
|
||||||
|
|
||||||
|
PNG_INTERNAL_FUNCTION(void,png_write_png_rows,(png_structrp png_ptr,
|
||||||
|
png_const_bytep *rows, png_uint_32 num_rows), PNG_EMPTY);
|
||||||
|
/* As above but rows[num_rows] of correctly (PNG) formated but unfiltered
|
||||||
|
* data are passed in. For an interlaced image the rows will be interlaced
|
||||||
|
* rows and therefore may be narrower than the image width.
|
||||||
|
*
|
||||||
|
* This function advances png_structp::pass and png_structp::row_number as
|
||||||
|
* required.
|
||||||
|
*/
|
||||||
|
|
||||||
/* Release memory used by the deflate mechanism */
|
/* Release memory used by the deflate mechanism */
|
||||||
PNG_INTERNAL_FUNCTION(void, png_deflate_destroy, (png_structp png_ptr),
|
PNG_INTERNAL_FUNCTION(void, png_deflate_destroy, (png_structp png_ptr),
|
||||||
PNG_EMPTY);
|
PNG_EMPTY);
|
||||||
|
67
pngstruct.h
67
pngstruct.h
@ -26,14 +26,14 @@
|
|||||||
#ifndef ZLIB_CONST
|
#ifndef ZLIB_CONST
|
||||||
/* We must ensure that zlib uses 'const' in declarations. */
|
/* We must ensure that zlib uses 'const' in declarations. */
|
||||||
# define ZLIB_CONST
|
# define ZLIB_CONST
|
||||||
#endif
|
#endif /* !ZLIB_CONST */
|
||||||
|
|
||||||
#include PNG_ZLIB_HEADER
|
#include PNG_ZLIB_HEADER
|
||||||
|
|
||||||
#ifdef const
|
#ifdef const
|
||||||
/* zlib.h sometimes #defines const to nothing, undo this. */
|
/* zlib.h sometimes #defines const to nothing, undo this. */
|
||||||
# undef const
|
# undef const
|
||||||
#endif
|
#endif /* const */
|
||||||
|
|
||||||
/* zlib.h has mediocre z_const use before 1.2.6, this stuff is for compatibility
|
/* zlib.h has mediocre z_const use before 1.2.6, this stuff is for compatibility
|
||||||
* with older builds.
|
* with older builds.
|
||||||
@ -41,10 +41,10 @@
|
|||||||
#if ZLIB_VERNUM < 0x1260
|
#if ZLIB_VERNUM < 0x1260
|
||||||
# define PNGZ_MSG_CAST(s) png_constcast(char*,s)
|
# define PNGZ_MSG_CAST(s) png_constcast(char*,s)
|
||||||
# define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b)
|
# define PNGZ_INPUT_CAST(b) png_constcast(png_bytep,b)
|
||||||
#else
|
#else /* ZLIB_VERNUM >= 0x1260 */
|
||||||
# define PNGZ_MSG_CAST(s) (s)
|
# define PNGZ_MSG_CAST(s) (s)
|
||||||
# define PNGZ_INPUT_CAST(b) (b)
|
# define PNGZ_INPUT_CAST(b) (b)
|
||||||
#endif
|
#endif /* ZLIB_VERNUM >= 0x1260 */
|
||||||
|
|
||||||
/* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib
|
/* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib
|
||||||
* can handle at once. This type need be no larger than 16 bits (so maximum of
|
* can handle at once. This type need be no larger than 16 bits (so maximum of
|
||||||
@ -57,17 +57,17 @@
|
|||||||
#ifndef ZLIB_IO_MAX
|
#ifndef ZLIB_IO_MAX
|
||||||
# ifdef __COVERITY__
|
# ifdef __COVERITY__
|
||||||
# define ZLIB_IO_MAX ((uInt)255U) /* else COVERITY whines */
|
# define ZLIB_IO_MAX ((uInt)255U) /* else COVERITY whines */
|
||||||
# else
|
# else /* !COVERITY */
|
||||||
# define ZLIB_IO_MAX ((uInt)-1)
|
# define ZLIB_IO_MAX ((uInt)-1)
|
||||||
# endif /* COVERITY */
|
# endif /* !COVERITY */
|
||||||
#endif
|
#endif /* !ZLIB_IO_MAX */
|
||||||
|
|
||||||
#ifdef PNG_WRITE_SUPPORTED
|
#ifdef PNG_WRITE_SUPPORTED
|
||||||
/* The write compression control (allocated on demand).
|
/* The write compression control (allocated on demand).
|
||||||
* TODO: use this for the read state too.
|
* TODO: use this for the read state too.
|
||||||
*/
|
*/
|
||||||
typedef struct png_zlib_state *png_zlib_statep;
|
typedef struct png_zlib_state *png_zlib_statep;
|
||||||
#endif
|
#endif /* WRITE */
|
||||||
|
|
||||||
/* Colorspace support; structures used in png_struct, png_info and in internal
|
/* Colorspace support; structures used in png_struct, png_info and in internal
|
||||||
* functions to hold and communicate information about the color space.
|
* functions to hold and communicate information about the color space.
|
||||||
@ -114,13 +114,13 @@ typedef struct png_colorspace
|
|||||||
{
|
{
|
||||||
#ifdef PNG_GAMMA_SUPPORTED
|
#ifdef PNG_GAMMA_SUPPORTED
|
||||||
png_fixed_point gamma; /* File gamma */
|
png_fixed_point gamma; /* File gamma */
|
||||||
#endif
|
#endif /* GAMMA */
|
||||||
|
|
||||||
#ifdef PNG_COLORSPACE_SUPPORTED
|
#ifdef PNG_COLORSPACE_SUPPORTED
|
||||||
png_xy end_points_xy; /* End points as chromaticities */
|
png_xy end_points_xy; /* End points as chromaticities */
|
||||||
png_XYZ end_points_XYZ; /* End points as CIE XYZ colorant values */
|
png_XYZ end_points_XYZ; /* End points as CIE XYZ colorant values */
|
||||||
png_uint_16 rendering_intent; /* Rendering intent of a profile */
|
png_uint_16 rendering_intent; /* Rendering intent of a profile */
|
||||||
#endif
|
#endif /* COLORSPACE */
|
||||||
|
|
||||||
/* Flags are always defined to simplify the code. */
|
/* Flags are always defined to simplify the code. */
|
||||||
png_uint_16 flags; /* As defined below */
|
png_uint_16 flags; /* As defined below */
|
||||||
@ -182,7 +182,7 @@ typedef struct
|
|||||||
* during PNG_TC_INIT_FINAL. The field is only used on read; write
|
* during PNG_TC_INIT_FINAL. The field is only used on read; write
|
||||||
* transforms do not modify the gamma of the data.
|
* transforms do not modify the gamma of the data.
|
||||||
*/
|
*/
|
||||||
# endif
|
# endif /* READ_GAMMA */
|
||||||
unsigned int format; /* As pngstruct::row_format below */
|
unsigned int format; /* As pngstruct::row_format below */
|
||||||
unsigned int range; /* Count of range transforms */
|
unsigned int range; /* Count of range transforms */
|
||||||
# define PNG_TC_CHANNELS(tc) PNG_FORMAT_CHANNELS((tc).format)
|
# define PNG_TC_CHANNELS(tc) PNG_FORMAT_CHANNELS((tc).format)
|
||||||
@ -364,7 +364,7 @@ struct png_struct_def
|
|||||||
* accessed.)
|
* accessed.)
|
||||||
*/
|
*/
|
||||||
jmp_buf jmp_buf_local;
|
jmp_buf jmp_buf_local;
|
||||||
#endif
|
#endif /* SETJMP */
|
||||||
|
|
||||||
/* Next the frequently accessed fields. Many processors perform arithmetic
|
/* Next the frequently accessed fields. Many processors perform arithmetic
|
||||||
* in the address pipeline, but frequently the amount of addition or
|
* in the address pipeline, but frequently the amount of addition or
|
||||||
@ -420,7 +420,7 @@ struct png_struct_def
|
|||||||
/* Options */
|
/* Options */
|
||||||
#ifdef PNG_SET_OPTION_SUPPORTED
|
#ifdef PNG_SET_OPTION_SUPPORTED
|
||||||
png_uint_32 options; /* On/off state (up to 16 options) */
|
png_uint_32 options; /* On/off state (up to 16 options) */
|
||||||
#endif
|
#endif /* SET_OPTIONS */
|
||||||
|
|
||||||
#ifdef PNG_READ_SUPPORTED
|
#ifdef PNG_READ_SUPPORTED
|
||||||
#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)
|
#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED)
|
||||||
@ -428,13 +428,13 @@ struct png_struct_def
|
|||||||
* is in (just) the info_struct.
|
* is in (just) the info_struct.
|
||||||
*/
|
*/
|
||||||
png_colorspace colorspace;
|
png_colorspace colorspace;
|
||||||
#endif
|
#endif /* COLORSPACE || GAMMA */
|
||||||
#endif /* READ */
|
#endif /* READ */
|
||||||
|
|
||||||
/* Transform handling */
|
/* Transform handling */
|
||||||
#ifdef PNG_TRANSFORM_MECH_SUPPORTED
|
#ifdef PNG_TRANSFORM_MECH_SUPPORTED
|
||||||
png_transformp transform_list; /* List of transformation to perform. */
|
png_transformp transform_list; /* List of transformation to perform. */
|
||||||
#endif
|
#endif /* TRANSFORM_MECH */
|
||||||
|
|
||||||
/* ROW BUFFERS and CONTROL
|
/* ROW BUFFERS and CONTROL
|
||||||
*
|
*
|
||||||
@ -442,9 +442,9 @@ struct png_struct_def
|
|||||||
* filter byte (which is in next_filter.) All fields are only used during
|
* filter byte (which is in next_filter.) All fields are only used during
|
||||||
* IDAT processing and start of 0.
|
* IDAT processing and start of 0.
|
||||||
*/
|
*/
|
||||||
#if defined(PNG_WRITE_FILTER_SUPPORTED) || defined(PNG_READ_SUPPORTED)
|
#ifdef PNG_READ_SUPPORTED
|
||||||
png_bytep row_buffer; /* primary row buffer */
|
png_bytep row_buffer; /* primary row buffer */
|
||||||
#endif /* WRITE_FILTER || READ */
|
#endif /* READ */
|
||||||
#if (defined(PNG_PROGRESSIVE_READ_SUPPORTED) ||\
|
#if (defined(PNG_PROGRESSIVE_READ_SUPPORTED) ||\
|
||||||
defined(PNG_READ_INTERLACING_SUPPORTED)) &&\
|
defined(PNG_READ_INTERLACING_SUPPORTED)) &&\
|
||||||
defined(PNG_TRANSFORM_MECH_SUPPORTED)
|
defined(PNG_TRANSFORM_MECH_SUPPORTED)
|
||||||
@ -482,10 +482,12 @@ struct png_struct_def
|
|||||||
unsigned int invalid_info; /* PNG_INFO_* for invalidated chunks */
|
unsigned int invalid_info; /* PNG_INFO_* for invalidated chunks */
|
||||||
unsigned int palette_updated:1; /* png_struct::palette changed */
|
unsigned int palette_updated:1; /* png_struct::palette changed */
|
||||||
#endif /* READ_TRANSFORMS */
|
#endif /* READ_TRANSFORMS */
|
||||||
|
#ifdef PNG_WRITE_SUPPORTED
|
||||||
|
unsigned int write_rows :1; /* libpng has complete rows to write */
|
||||||
|
#endif /* WRITE */
|
||||||
#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
|
#ifdef PNG_SEQUENTIAL_READ_SUPPORTED
|
||||||
unsigned int read_started :1; /* at least one call to png_read_row */
|
unsigned int read_started :1; /* at least one call to png_read_row */
|
||||||
#endif
|
#endif /* SEQUENTIAL_READ */
|
||||||
#if defined (PNG_READ_INTERLACING_SUPPORTED) ||\
|
#if defined (PNG_READ_INTERLACING_SUPPORTED) ||\
|
||||||
defined (PNG_WRITE_INTERLACING_SUPPORTED)
|
defined (PNG_WRITE_INTERLACING_SUPPORTED)
|
||||||
unsigned int do_interlace :1; /* libpng handles the interlace */
|
unsigned int do_interlace :1; /* libpng handles the interlace */
|
||||||
@ -574,7 +576,7 @@ struct png_struct_def
|
|||||||
* available to zlib during read decompression.
|
* available to zlib during read decompression.
|
||||||
*/
|
*/
|
||||||
png_alloc_size_t read_buffer_size; /* current size of the buffer */
|
png_alloc_size_t read_buffer_size; /* current size of the buffer */
|
||||||
#endif
|
#endif /* READ */
|
||||||
|
|
||||||
#if defined(PNG_SEQUENTIAL_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
|
#if defined(PNG_SEQUENTIAL_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
|
||||||
png_uint_32 IDAT_size; /* limit on IDAT read and write IDAT size */
|
png_uint_32 IDAT_size; /* limit on IDAT read and write IDAT size */
|
||||||
@ -585,13 +587,13 @@ struct png_struct_def
|
|||||||
jmp_buf *jmp_buf_ptr; /* passed to longjmp_fn */
|
jmp_buf *jmp_buf_ptr; /* passed to longjmp_fn */
|
||||||
png_longjmp_ptr longjmp_fn; /* setjmp non-local goto function. */
|
png_longjmp_ptr longjmp_fn; /* setjmp non-local goto function. */
|
||||||
size_t jmp_buf_size; /* size of *jmp_buf_ptr, if allocated */
|
size_t jmp_buf_size; /* size of *jmp_buf_ptr, if allocated */
|
||||||
#endif
|
#endif /* SETJMP */
|
||||||
|
|
||||||
/* Error/warning callbacks */
|
/* Error/warning callbacks */
|
||||||
png_error_ptr error_fn; /* print an error message and abort */
|
png_error_ptr error_fn; /* print an error message and abort */
|
||||||
#ifdef PNG_WARNINGS_SUPPORTED
|
#ifdef PNG_WARNINGS_SUPPORTED
|
||||||
png_error_ptr warning_fn; /* print a warning and continue */
|
png_error_ptr warning_fn; /* print a warning and continue */
|
||||||
#endif
|
#endif /* WARNINGS */
|
||||||
png_voidp error_ptr; /* user supplied data for the above */
|
png_voidp error_ptr; /* user supplied data for the above */
|
||||||
|
|
||||||
/* MEMORY ALLOCATION */
|
/* MEMORY ALLOCATION */
|
||||||
@ -599,7 +601,7 @@ struct png_struct_def
|
|||||||
png_malloc_ptr malloc_fn; /* allocate memory */
|
png_malloc_ptr malloc_fn; /* allocate memory */
|
||||||
png_free_ptr free_fn; /* free memory */
|
png_free_ptr free_fn; /* free memory */
|
||||||
png_voidp mem_ptr; /* user supplied data for the above */
|
png_voidp mem_ptr; /* user supplied data for the above */
|
||||||
#endif
|
#endif /* USER_MEM */
|
||||||
|
|
||||||
/* IO and BASIC READ/WRITE SUPPORT */
|
/* IO and BASIC READ/WRITE SUPPORT */
|
||||||
png_voidp io_ptr; /* user supplied data for IO callbacks */
|
png_voidp io_ptr; /* user supplied data for IO callbacks */
|
||||||
@ -622,8 +624,7 @@ struct png_struct_def
|
|||||||
|
|
||||||
#ifdef PNG_WRITE_FLUSH_SUPPORTED
|
#ifdef PNG_WRITE_FLUSH_SUPPORTED
|
||||||
png_flush_ptr output_flush_fn; /* Function for flushing output */
|
png_flush_ptr output_flush_fn; /* Function for flushing output */
|
||||||
#endif
|
#endif /* WRITE_FLUSH */
|
||||||
|
|
||||||
#endif /* WRITE */
|
#endif /* WRITE */
|
||||||
|
|
||||||
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
|
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
|
||||||
@ -634,14 +635,14 @@ struct png_struct_def
|
|||||||
* - it is decremented as memory is allocated.
|
* - it is decremented as memory is allocated.
|
||||||
*/
|
*/
|
||||||
png_alloc_size_t user_chunk_malloc_max;
|
png_alloc_size_t user_chunk_malloc_max;
|
||||||
#endif
|
#endif /* SET_USER_LIMITS */
|
||||||
#ifdef PNG_USER_LIMITS_SUPPORTED
|
#ifdef PNG_USER_LIMITS_SUPPORTED
|
||||||
/* limit on total *number* of sPLT, text and unknown chunks that can be
|
/* limit on total *number* of sPLT, text and unknown chunks that can be
|
||||||
* stored. 0 means unlimited. This field is a counter - it is decremented
|
* stored. 0 means unlimited. This field is a counter - it is decremented
|
||||||
* as chunks are encountered.
|
* as chunks are encountered.
|
||||||
*/
|
*/
|
||||||
png_uint_32 user_chunk_cache_max;
|
png_uint_32 user_chunk_cache_max;
|
||||||
#endif
|
#endif /* USER_LIMITS */
|
||||||
|
|
||||||
/* The progressive reader gets passed data and calls application handling
|
/* The progressive reader gets passed data and calls application handling
|
||||||
* functions when appropriate.
|
* functions when appropriate.
|
||||||
@ -672,7 +673,7 @@ struct png_struct_def
|
|||||||
|
|
||||||
#ifdef PNG_IO_STATE_SUPPORTED
|
#ifdef PNG_IO_STATE_SUPPORTED
|
||||||
png_uint_32 io_state; /* tells the app read/write progress */
|
png_uint_32 io_state; /* tells the app read/write progress */
|
||||||
#endif
|
#endif /* IO_STATE */
|
||||||
|
|
||||||
/* UNKNOWN CHUNK HANDLING */
|
/* UNKNOWN CHUNK HANDLING */
|
||||||
/* TODO: this is excessively complicated, there are multiple ways of doing
|
/* TODO: this is excessively complicated, there are multiple ways of doing
|
||||||
@ -686,12 +687,12 @@ struct png_struct_def
|
|||||||
* set_unknown_chunks interface.)
|
* set_unknown_chunks interface.)
|
||||||
*/
|
*/
|
||||||
png_voidp user_chunk_ptr;
|
png_voidp user_chunk_ptr;
|
||||||
#endif
|
#endif /* USER_CHUNKS */
|
||||||
|
|
||||||
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
|
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
|
||||||
/* This is called back from the unknown chunk handling */
|
/* This is called back from the unknown chunk handling */
|
||||||
png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */
|
png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */
|
||||||
#endif
|
#endif /* READ_USER_CHUNKS */
|
||||||
|
|
||||||
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
|
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
|
||||||
png_uint_32 known_unknown; /* Bit mask of known chunks to be treated as
|
png_uint_32 known_unknown; /* Bit mask of known chunks to be treated as
|
||||||
@ -703,7 +704,7 @@ struct png_struct_def
|
|||||||
* 'known & ~save'.
|
* 'known & ~save'.
|
||||||
*/
|
*/
|
||||||
# define png_IDATs_skipped(pp) (((pp)->known_unknown & ~(pp)->save_unknown)&1U)
|
# define png_IDATs_skipped(pp) (((pp)->known_unknown & ~(pp)->save_unknown)&1U)
|
||||||
#else
|
#else /* !SAVE_UNKNOWN_CHUNKS */
|
||||||
# define png_IDATs_skipped(pp) ((pp)->known_unknown & 1U)
|
# define png_IDATs_skipped(pp) ((pp)->known_unknown & 1U)
|
||||||
#endif /* !SAVE_UNKNOWN_CHUNKS */
|
#endif /* !SAVE_UNKNOWN_CHUNKS */
|
||||||
#endif /* HANDLE_AS_UNKNOWN */
|
#endif /* HANDLE_AS_UNKNOWN */
|
||||||
@ -713,7 +714,7 @@ struct png_struct_def
|
|||||||
* followed by a PNG_HANDLE_* byte */
|
* followed by a PNG_HANDLE_* byte */
|
||||||
unsigned int unknown_default :2; /* As PNG_HANDLE_* */
|
unsigned int unknown_default :2; /* As PNG_HANDLE_* */
|
||||||
unsigned int num_chunk_list; /* Number of entries in the list */
|
unsigned int num_chunk_list; /* Number of entries in the list */
|
||||||
#endif
|
#endif /* SET_UNKNOWN_CHUNKS */
|
||||||
|
|
||||||
/* COMPRESSION AND DECOMPRESSION SUPPORT.
|
/* COMPRESSION AND DECOMPRESSION SUPPORT.
|
||||||
*
|
*
|
||||||
@ -738,7 +739,7 @@ struct png_struct_def
|
|||||||
/* MNG SUPPORT */
|
/* MNG SUPPORT */
|
||||||
#ifdef PNG_MNG_FEATURES_SUPPORTED
|
#ifdef PNG_MNG_FEATURES_SUPPORTED
|
||||||
unsigned int mng_features_permitted :3;
|
unsigned int mng_features_permitted :3;
|
||||||
#endif
|
#endif /* MNG_FEATURES */
|
||||||
|
|
||||||
/* SCRATCH buffers, used when control returns to the application or a read
|
/* SCRATCH buffers, used when control returns to the application or a read
|
||||||
* loop.
|
* loop.
|
||||||
|
BIN
pngtest.png
BIN
pngtest.png
Binary file not shown.
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
11
pngwio.c
11
pngwio.c
@ -67,18 +67,7 @@ png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* This function is called to output any data pending writing (normally
|
|
||||||
* to disk). After png_flush is called, there should be no data pending
|
|
||||||
* writing in any buffers.
|
|
||||||
*/
|
|
||||||
#ifdef PNG_WRITE_FLUSH_SUPPORTED
|
#ifdef PNG_WRITE_FLUSH_SUPPORTED
|
||||||
void /* PRIVATE */
|
|
||||||
png_flush(png_structrp png_ptr)
|
|
||||||
{
|
|
||||||
if (png_ptr->output_flush_fn != NULL)
|
|
||||||
png_ptr->output_flush_fn(png_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
# ifdef PNG_STDIO_SUPPORTED
|
# ifdef PNG_STDIO_SUPPORTED
|
||||||
void PNGCBAPI
|
void PNGCBAPI
|
||||||
png_default_flush(png_structp png_ptr)
|
png_default_flush(png_structp png_ptr)
|
||||||
|
416
pngwrite.c
416
pngwrite.c
@ -487,7 +487,8 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr)
|
|||||||
*/
|
*/
|
||||||
# ifdef PNG_WRITE_FLUSH_SUPPORTED
|
# ifdef PNG_WRITE_FLUSH_SUPPORTED
|
||||||
# ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED
|
# ifdef PNG_WRITE_FLUSH_AFTER_IEND_SUPPORTED
|
||||||
png_flush(png_ptr);
|
if (png_ptr->output_flush_fn != NULL)
|
||||||
|
png_ptr->output_flush_fn(png_ptr);
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
}
|
}
|
||||||
@ -570,65 +571,6 @@ png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Write a few rows of image data. If the image is interlaced,
|
|
||||||
* either you will have to write the 7 sub images, or, if you
|
|
||||||
* have called png_set_interlace_handling(), you will have to
|
|
||||||
* "write" the image seven times.
|
|
||||||
*/
|
|
||||||
void PNGAPI
|
|
||||||
png_write_rows(png_structrp png_ptr, png_bytepp row,
|
|
||||||
png_uint_32 num_rows)
|
|
||||||
{
|
|
||||||
png_debug(1, "in png_write_rows");
|
|
||||||
|
|
||||||
if (png_ptr == NULL || row == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
/* Loop through the rows */
|
|
||||||
while (num_rows-- > 0)
|
|
||||||
png_write_row(png_ptr, *row++);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write the image. You only need to call this function once, even
|
|
||||||
* if you are writing an interlaced image.
|
|
||||||
*/
|
|
||||||
void PNGAPI
|
|
||||||
png_write_image(png_structrp png_ptr, png_bytepp image)
|
|
||||||
{
|
|
||||||
int num_pass; /* pass variables */
|
|
||||||
|
|
||||||
if (png_ptr == NULL || image == NULL)
|
|
||||||
return;
|
|
||||||
|
|
||||||
png_debug(1, "in png_write_image");
|
|
||||||
|
|
||||||
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
|
|
||||||
/* Initialize interlace handling. If image is not interlaced,
|
|
||||||
* this will set pass to 1
|
|
||||||
*/
|
|
||||||
num_pass = png_set_interlace_handling(png_ptr);
|
|
||||||
#else
|
|
||||||
num_pass = 1;
|
|
||||||
|
|
||||||
if (png_ptr->interlaced)
|
|
||||||
{
|
|
||||||
png_app_error(png_ptr, "no interlace support");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Loop through passes */
|
|
||||||
while (num_pass-- > 0)
|
|
||||||
{
|
|
||||||
png_bytepp rp = image; /* points to current row */
|
|
||||||
png_uint_32 num_rows = png_ptr->height;
|
|
||||||
|
|
||||||
/* Loop through image */
|
|
||||||
while (num_rows-- > 0)
|
|
||||||
png_write_row(png_ptr, *rp++);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(PNG_WRITE_INTERLACING_SUPPORTED) ||\
|
#if defined(PNG_WRITE_INTERLACING_SUPPORTED) ||\
|
||||||
defined(PNG_WRITE_TRANSFORMS_SUPPORTED)
|
defined(PNG_WRITE_TRANSFORMS_SUPPORTED)
|
||||||
static void
|
static void
|
||||||
@ -707,10 +649,10 @@ write_row_buffered(png_structrp png_ptr,
|
|||||||
}
|
}
|
||||||
# endif /* WRITE_TRANSFORMS */
|
# endif /* WRITE_TRANSFORMS */
|
||||||
|
|
||||||
/* Call png_write_filter_row to write this block of data, the test on
|
/* Call png_write_png_data to write this block of data, the test on
|
||||||
* maxpixels says if this is the final block in the row.
|
* maxpixels says if this is the final block in the row.
|
||||||
*/
|
*/
|
||||||
png_write_filter_row(png_ptr, prev_pixels, pixel_buffer.buffer, x,
|
png_write_png_data(png_ptr, prev_pixels, pixel_buffer.buffer, x,
|
||||||
max_pixels, row_info_flags);
|
max_pixels, row_info_flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -824,47 +766,7 @@ interlace_row_byte(png_const_structrp png_ptr, png_bytep dp, png_const_bytep sp,
|
|||||||
}
|
}
|
||||||
#endif /* WRITE_INTERLACING */
|
#endif /* WRITE_INTERLACING */
|
||||||
|
|
||||||
static void
|
#ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
|
||||||
write_row_unbuffered(png_structrp png_ptr, png_const_bytep row,
|
|
||||||
unsigned int row_info_flags)
|
|
||||||
{
|
|
||||||
/* Split the row into blocks of the appropriate size: */
|
|
||||||
const unsigned int input_depth = png_ptr->row_input_pixel_depth;
|
|
||||||
unsigned int max_pixels = png_max_pixel_block(png_ptr);
|
|
||||||
png_uint_32 max_bytes = max_pixels;
|
|
||||||
const unsigned int pass = png_ptr->pass;
|
|
||||||
const png_uint_32 width = png_ptr->interlaced == PNG_INTERLACE_NONE ?
|
|
||||||
png_ptr->width : PNG_PASS_COLS(png_ptr->width, pass);
|
|
||||||
png_uint_32 x;
|
|
||||||
png_byte prev_pixels[4*2*2]; /* 2 pixels up to 4 2-byte channels each */
|
|
||||||
|
|
||||||
/* max_pixels is at most 16 bits, input_depth is at most 64, so the product
|
|
||||||
* always fits in 32 bits:
|
|
||||||
*/
|
|
||||||
max_bytes *= input_depth; /* bits */
|
|
||||||
debug(input_depth <= 64 && (max_bytes & 7U) == 0U);
|
|
||||||
max_bytes >>= 3;
|
|
||||||
|
|
||||||
memset(prev_pixels, 0U, sizeof prev_pixels);
|
|
||||||
|
|
||||||
for (x = 0U; x < width; x += max_pixels, row += max_bytes)
|
|
||||||
{
|
|
||||||
if (max_pixels > width - x)
|
|
||||||
{
|
|
||||||
max_bytes = width - x;
|
|
||||||
max_pixels = (unsigned int)/*SAFE*/max_bytes;
|
|
||||||
max_bytes = (max_bytes * input_depth + 7U) >> 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug((row_info_flags & png_row_end) == 0U); /* must be set here at end */
|
|
||||||
if (x + max_pixels >= width)
|
|
||||||
row_info_flags |= png_row_end;
|
|
||||||
|
|
||||||
png_write_filter_row(png_ptr, prev_pixels, row, x, max_pixels,
|
|
||||||
row_info_flags);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
write_row_core(png_structrp png_ptr, png_const_bytep row,
|
write_row_core(png_structrp png_ptr, png_const_bytep row,
|
||||||
unsigned int row_info_flags)
|
unsigned int row_info_flags)
|
||||||
@ -880,7 +782,8 @@ write_row_core(png_structrp png_ptr, png_const_bytep row,
|
|||||||
/* If control reaches this point the intermediate buffer is not required and
|
/* If control reaches this point the intermediate buffer is not required and
|
||||||
* the input data can be used unmodified.
|
* the input data can be used unmodified.
|
||||||
*/
|
*/
|
||||||
write_row_unbuffered(png_ptr, row, row_info_flags);
|
png_write_png_rows(png_ptr, &row, 1U);
|
||||||
|
PNG_UNUSED(row_info_flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write a single non-interlaced row. */
|
/* Write a single non-interlaced row. */
|
||||||
@ -888,75 +791,53 @@ static void
|
|||||||
write_row_non_interlaced(png_structrp png_ptr, png_const_bytep row)
|
write_row_non_interlaced(png_structrp png_ptr, png_const_bytep row)
|
||||||
{
|
{
|
||||||
const png_uint_32 row_number = png_ptr->row_number+1U;
|
const png_uint_32 row_number = png_ptr->row_number+1U;
|
||||||
const int last_pass_row = row_number == png_ptr->height;
|
|
||||||
|
|
||||||
/* There is only one pass, so this is the last pass: */
|
/* There is only one pass, so this is the last pass: */
|
||||||
write_row_core(png_ptr, row,
|
const unsigned int row_info_flags =
|
||||||
(row_number == 1U ? png_pass_first_row : 0) |
|
(row_number == 1U ? png_pass_first_row : 0) |
|
||||||
(last_pass_row ? png_pass_last_row : 0) |
|
(row_number >= png_ptr->height ? png_pass_last_row : 0) |
|
||||||
png_pass_last);
|
png_pass_last;
|
||||||
|
|
||||||
if (!last_pass_row)
|
debug(png_ptr->interlaced == PNG_INTERLACE_NONE);
|
||||||
png_ptr->row_number = row_number;
|
|
||||||
|
|
||||||
else
|
write_row_core(png_ptr, row, row_info_flags);
|
||||||
{
|
|
||||||
png_ptr->row_number = 0U;
|
|
||||||
png_ptr->pass = 7U;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write a single interlaced row. */
|
/* Write a single interlaced row. */
|
||||||
static void
|
static void
|
||||||
write_row_interlaced(png_structrp png_ptr, png_const_bytep row)
|
write_row_interlaced(png_structrp png_ptr, png_const_bytep row)
|
||||||
{
|
{
|
||||||
/* row_number is the row in the pass. The app must only call png_write_row
|
|
||||||
* the correct number of times. 'pass' is set to 7U after the end.
|
|
||||||
*/
|
|
||||||
const png_uint_32 row_number = png_ptr->row_number+1U;
|
const png_uint_32 row_number = png_ptr->row_number+1U;
|
||||||
unsigned int pass = png_ptr->pass;
|
const png_uint_32 height = png_ptr->height;
|
||||||
const int last_pass_row = row_number == PNG_PASS_ROWS(png_ptr->height, pass);
|
const unsigned int pass = png_ptr->pass;
|
||||||
|
const unsigned int row_info_flags =
|
||||||
|
(row_number == 1U ? png_pass_first_row : 0) |
|
||||||
|
(row_number == PNG_PASS_ROWS(height, pass) ? png_pass_last_row : 0) |
|
||||||
|
(pass == PNG_LAST_PASS(png_ptr->width, height) ? png_pass_last : 0);
|
||||||
|
|
||||||
write_row_core(png_ptr, row,
|
# ifdef PNG_WRITE_INTERLACING_SUPPORTED
|
||||||
(row_number == 1U ? png_pass_first_row : 0) |
|
/* Check that libpng is not doing the interlace: */
|
||||||
(last_pass_row ? png_pass_last_row : 0) |
|
debug(png_ptr->interlaced != PNG_INTERLACE_NONE &&
|
||||||
(pass == PNG_LAST_PASS(png_ptr->width, png_ptr->height) ?
|
!png_ptr->do_interlace);
|
||||||
png_pass_last : 0));
|
# endif /* WRITE_INTERLACING */
|
||||||
|
|
||||||
if (!last_pass_row)
|
write_row_core(png_ptr, row, row_info_flags);
|
||||||
png_ptr->row_number = row_number;
|
|
||||||
|
|
||||||
else
|
|
||||||
{
|
|
||||||
png_ptr->row_number = 0U;
|
|
||||||
|
|
||||||
do
|
|
||||||
++pass;
|
|
||||||
while (pass < 7U &&
|
|
||||||
!PNG_PASS_IN_IMAGE(png_ptr->width, png_ptr->height, pass));
|
|
||||||
|
|
||||||
png_ptr->pass = 0x7U & pass;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
#endif /* WRITE_TRANSFORMS */
|
||||||
|
|
||||||
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
|
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
|
||||||
/* Interlace a row then write it out. */
|
/* Interlace a row then write it out. */
|
||||||
static int
|
static void
|
||||||
interlace_row(png_structrp png_ptr, png_const_bytep row)
|
interlace_row(png_structrp png_ptr, png_const_bytep row)
|
||||||
{
|
{
|
||||||
/* row_number is in the image, it may not be in the pass and, likewise, the
|
/* The row may not exist in the image (for this pass). */
|
||||||
* pass may not exist.
|
|
||||||
*/
|
|
||||||
const png_uint_32 row_number = png_ptr->row_number; /* in image */
|
const png_uint_32 row_number = png_ptr->row_number; /* in image */
|
||||||
const unsigned int pass = png_ptr->pass;
|
const unsigned int pass = png_ptr->pass;
|
||||||
const int write_row = png_ptr->width > PNG_PASS_START_COL(pass) &&
|
|
||||||
PNG_ROW_IN_INTERLACE_PASS(row_number, pass);
|
|
||||||
|
|
||||||
if (write_row)
|
if (png_ptr->width > PNG_PASS_START_COL(pass) &&
|
||||||
|
PNG_ROW_IN_INTERLACE_PASS(row_number, pass))
|
||||||
{
|
{
|
||||||
const unsigned int row_info_flags =
|
const unsigned int row_info_flags =
|
||||||
(row_number == PNG_PASS_START_ROW(pass) ?
|
(row_number == PNG_PASS_START_ROW(pass) ? png_pass_first_row : 0) |
|
||||||
png_pass_first_row : 0) |
|
|
||||||
(PNG_LAST_PASS_ROW(row_number, pass, png_ptr->height) ?
|
(PNG_LAST_PASS_ROW(row_number, pass, png_ptr->height) ?
|
||||||
png_pass_last_row : 0) |
|
png_pass_last_row : 0) |
|
||||||
(pass == PNG_LAST_PASS(png_ptr->width, png_ptr->height) ?
|
(pass == PNG_LAST_PASS(png_ptr->width, png_ptr->height) ?
|
||||||
@ -991,79 +872,214 @@ interlace_row(png_structrp png_ptr, png_const_bytep row)
|
|||||||
interlace_row_byte, input_depth >> 3);
|
interlace_row_byte, input_depth >> 3);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
} /* pass < 6 */
|
||||||
|
|
||||||
else /* pass 6; no interlacing required */
|
else /* pass 6: no interlacing required */
|
||||||
write_row_core(png_ptr, row, row_info_flags);
|
write_row_core(png_ptr, row, row_info_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row_number+1U < png_ptr->height)
|
|
||||||
png_ptr->row_number = row_number+1U;
|
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
png_ptr->row_number = 0U;
|
/* This code must advance row_number/pass itself; the row has been
|
||||||
png_ptr->pass = 0x7U & (pass+1U);
|
* skipped.
|
||||||
}
|
*/
|
||||||
|
if (row_number+1U < png_ptr->height)
|
||||||
|
png_ptr->row_number = row_number+1U;
|
||||||
|
|
||||||
return write_row;
|
else
|
||||||
|
{
|
||||||
|
png_ptr->row_number = 0U;
|
||||||
|
png_ptr->pass = 0x7U & (pass+1U);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* WRITE_INTERLACING */
|
#endif /* WRITE_INTERLACING */
|
||||||
|
|
||||||
/* Called by user to write a row of image data */
|
/* Bottleneck API to actually write a number of rows, only exists because the
|
||||||
void PNGAPI
|
* rows parameter to png_write_rows is wrong.
|
||||||
png_write_row(png_structrp png_ptr, png_const_bytep row)
|
*/
|
||||||
|
static void
|
||||||
|
png_write_rows_internal(png_structrp png_ptr, png_const_bytep *rows,
|
||||||
|
png_uint_32 num_rows)
|
||||||
{
|
{
|
||||||
if (png_ptr != NULL)
|
if (png_ptr != NULL && num_rows > 0U && rows != NULL)
|
||||||
{
|
{
|
||||||
const unsigned int pass = png_ptr->pass;
|
|
||||||
const png_uint_32 row_number = png_ptr->row_number;
|
|
||||||
|
|
||||||
/* Unlike the read code initialization happens automatically: */
|
/* Unlike the read code initialization happens automatically: */
|
||||||
if (row_number == 0 && pass == 0)
|
if (png_ptr->row_number == 0U && png_ptr->pass == 0U)
|
||||||
png_write_start_IDAT(png_ptr); /* doesn't change row/pass/width */
|
{
|
||||||
|
png_init_row_info(png_ptr);
|
||||||
|
|
||||||
else if (pass == 7U) /* too many calls; write already ended */
|
# ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
|
||||||
|
/* If the app takes a png_info from a read operation and if the app has
|
||||||
|
* performed transforms on the data the png_info can contain IHDR
|
||||||
|
* information that cannot be represented in PNG. The code that writes
|
||||||
|
* the IHDR takes the color type from the png_info::format. The app
|
||||||
|
* adds transforms, before or after writing the IHDR, then the IHDR
|
||||||
|
* color_type stored in png_struct::color_type is used in
|
||||||
|
* png_init_row_info above to work out the actual row format.
|
||||||
|
*
|
||||||
|
* Prior to 1.7.0 this was not verified (there was no easy way to do
|
||||||
|
* so). Now we can check it here, however this is an:
|
||||||
|
*
|
||||||
|
* API CHANGE: in 1.7.0 an error may be flagged against bogus
|
||||||
|
* info_struct formats even though the app had removed them itself.
|
||||||
|
* It's just a warning at present.
|
||||||
|
*
|
||||||
|
* The test is that either the row_format produced by the write
|
||||||
|
* transforms exactly matches that in the original info_struct::format
|
||||||
|
* or that the info_struct::format was a simple mapping of the
|
||||||
|
* color_type that ended up in the IHDR:
|
||||||
|
*/
|
||||||
|
if (png_ptr->row_format != png_ptr->info_format &&
|
||||||
|
PNG_FORMAT_FROM_COLOR_TYPE(png_ptr->color_type) !=
|
||||||
|
png_ptr->info_format)
|
||||||
|
png_app_warning(png_ptr, "info_struct format does not match IHDR");
|
||||||
|
# endif /* WRITE_TRANSFORMS */
|
||||||
|
|
||||||
|
/* Perform initialization required before IDATs are written. */
|
||||||
|
png_write_start_IDAT(png_ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
else if (png_ptr->pass >= 7U) /* too many calls; write already ended */
|
||||||
{
|
{
|
||||||
debug(png_ptr->row_number == 0U);
|
debug(png_ptr->row_number == 0U);
|
||||||
png_app_error(png_ptr, "Too many calls to png_write_row");
|
png_app_error(png_ptr, "Too many calls to png_write_row");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Make sure there is a row to write: */
|
/* The remainder of these tests detect internal errors in libpng */
|
||||||
if (row == NULL)
|
else if (png_ptr->interlaced == PNG_INTERLACE_NONE)
|
||||||
{
|
affirm(png_ptr->row_number < png_ptr->height && png_ptr->pass == 0U);
|
||||||
png_app_error(png_ptr, "NULL row pointer to png_write_row");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (png_ptr->interlaced == PNG_INTERLACE_NONE)
|
|
||||||
write_row_non_interlaced(png_ptr, row);
|
|
||||||
|
|
||||||
# ifdef PNG_WRITE_INTERLACING_SUPPORTED
|
# ifdef PNG_WRITE_INTERLACING_SUPPORTED
|
||||||
/* Optional: libpng does the interlacing, app passes every row of the
|
else if (png_ptr->do_interlace)
|
||||||
* image the required number of times.
|
affirm(png_ptr->row_number < png_ptr->height);
|
||||||
*/
|
# endif /* WRITE_INTERLACING */
|
||||||
else if (png_ptr->do_interlace != 0U)
|
|
||||||
{
|
|
||||||
if (!interlace_row(png_ptr, row))
|
|
||||||
return; /* row skipped; skip the write callback */
|
|
||||||
}
|
|
||||||
# endif
|
|
||||||
|
|
||||||
else /* app does the interlacing */
|
else /* app does interlace */
|
||||||
write_row_interlaced(png_ptr, row);
|
affirm(
|
||||||
|
PNG_PASS_IN_IMAGE(png_ptr->width, png_ptr->height, png_ptr->pass) &&
|
||||||
|
png_ptr->row_number < PNG_PASS_ROWS(png_ptr->height, png_ptr->pass)
|
||||||
|
);
|
||||||
|
|
||||||
/* API CHANGE: 1.7.0: this is now called after png_struct::row_number and
|
/* First handle rows that require buffering because of the need to
|
||||||
* png_struct::pass have been updated and, at the end of the image, after
|
* interlace them or the need to perform write transforms.
|
||||||
* the deflate stream has been closed. The order of the call with respect
|
|
||||||
* to the flush operation has also changed. The callback can't discover
|
|
||||||
* any of this unless it relies on the write callbacks to find the row
|
|
||||||
* data, and that was never predictable.
|
|
||||||
*/
|
*/
|
||||||
if (png_ptr->write_row_fn != NULL)
|
# ifdef PNG_WRITE_INTERLACING_SUPPORTED
|
||||||
(*(png_ptr->write_row_fn))(png_ptr, row_number, pass);
|
/* libpng is doing the interlacing, but this only makes a difference to
|
||||||
} /* png_ptr != NULL */
|
* the first six passes (numbered, in libpng, 0..5); the seventh pass
|
||||||
|
* (numbered 6 by libpng) consists of complete image rows.
|
||||||
|
*/
|
||||||
|
if (png_ptr->do_interlace) while (num_rows > 0U && png_ptr->pass < 6)
|
||||||
|
interlace_row(png_ptr, *rows++), --num_rows;
|
||||||
|
# endif /* WRITE_INTERLACING */
|
||||||
|
|
||||||
|
# ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
|
||||||
|
/* Transforms required however the row interlacing has already been
|
||||||
|
* handled and we have a complete (PNG) row.
|
||||||
|
*/
|
||||||
|
if (png_ptr->transform_list != NULL)
|
||||||
|
{
|
||||||
|
if (png_ptr->interlaced == PNG_INTERLACE_NONE)
|
||||||
|
while (num_rows > 0U)
|
||||||
|
write_row_non_interlaced(png_ptr, *rows++), --num_rows;
|
||||||
|
|
||||||
|
# ifdef PNG_WRITE_INTERLACING_SUPPORTED
|
||||||
|
else if (png_ptr->do_interlace)
|
||||||
|
while (num_rows > 0U)
|
||||||
|
interlace_row(png_ptr, *rows++), --num_rows;
|
||||||
|
# endif /* WRITE_INTERLACING */
|
||||||
|
|
||||||
|
else /* app does the interlacing */
|
||||||
|
while (num_rows > 0U)
|
||||||
|
write_row_interlaced(png_ptr, *rows++), --num_rows;
|
||||||
|
}
|
||||||
|
# endif /* WRITE_TRANSFORMS */
|
||||||
|
|
||||||
|
/* Finally handle any remaining rows that require no (libpng) interlace
|
||||||
|
* and no transforms.
|
||||||
|
*/
|
||||||
|
if (num_rows > 0U)
|
||||||
|
png_write_png_rows(png_ptr, rows, num_rows);
|
||||||
|
|
||||||
|
/* Repeat the checks above, but allow for end-of-image. */
|
||||||
|
if (png_ptr->pass < 7U)
|
||||||
|
{
|
||||||
|
if (png_ptr->interlaced == PNG_INTERLACE_NONE)
|
||||||
|
affirm(png_ptr->row_number < png_ptr->height &&
|
||||||
|
png_ptr->pass == 0U);
|
||||||
|
|
||||||
|
# ifdef PNG_WRITE_INTERLACING_SUPPORTED
|
||||||
|
else if (png_ptr->do_interlace)
|
||||||
|
affirm(png_ptr->row_number < png_ptr->height);
|
||||||
|
# endif /* WRITE_INTERLACING */
|
||||||
|
|
||||||
|
else /* app does interlace */
|
||||||
|
affirm(PNG_PASS_IN_IMAGE(png_ptr->width, png_ptr->height,
|
||||||
|
png_ptr->pass) &&
|
||||||
|
png_ptr->row_number <
|
||||||
|
PNG_PASS_ROWS(png_ptr->height, png_ptr->pass));
|
||||||
|
}
|
||||||
|
} /* png_ptr, rows, num_rows all valid */
|
||||||
|
|
||||||
|
else if (png_ptr != NULL)
|
||||||
|
png_app_warning(png_ptr, "Missing rows to row write API");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ROW WRITE APIs */
|
||||||
|
/* Called by user to write a single row of image data */
|
||||||
|
void PNGAPI
|
||||||
|
png_write_row(png_structrp png_ptr, png_const_bytep row)
|
||||||
|
{
|
||||||
|
png_debug(1, "in png_write_row");
|
||||||
|
png_write_rows_internal(png_ptr, &row, 1U);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write a few rows of image data. If the image is interlaced,
|
||||||
|
* either you will have to write the 7 sub images, or, if you
|
||||||
|
* have called png_set_interlace_handling(), you will have to
|
||||||
|
* "write" the image seven times.
|
||||||
|
*/
|
||||||
|
void PNGAPI
|
||||||
|
png_write_rows(png_structrp png_ptr, png_bytepp rows, png_uint_32 num_rows)
|
||||||
|
{
|
||||||
|
png_debug(1, "in png_write_rows");
|
||||||
|
|
||||||
|
if (png_ptr != NULL)
|
||||||
|
png_write_rows_internal(png_ptr, png_constcast(png_const_bytep*,rows),
|
||||||
|
num_rows);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Write the image. You only need to call this function once, even
|
||||||
|
* if you are writing an interlaced image.
|
||||||
|
*/
|
||||||
|
void PNGAPI
|
||||||
|
png_write_image(png_structrp png_ptr, png_bytepp image)
|
||||||
|
{
|
||||||
|
png_debug(1, "in png_write_image");
|
||||||
|
|
||||||
|
if (png_ptr != NULL)
|
||||||
|
{
|
||||||
|
int num_pass = 1;
|
||||||
|
|
||||||
|
/* The image is always an non-interlaced image. To write it as interlaced
|
||||||
|
* interlace handling must be present:
|
||||||
|
*/
|
||||||
|
if (png_ptr->interlaced)
|
||||||
|
{
|
||||||
|
# ifdef PNG_WRITE_INTERLACING_SUPPORTED
|
||||||
|
num_pass = png_set_interlace_handling(png_ptr);
|
||||||
|
# else /* !WRITE_INTERLACING */
|
||||||
|
/* There is no recovery because the IHDR has already been written.
|
||||||
|
*/
|
||||||
|
png_error(png_ptr, "No interlace support");
|
||||||
|
# endif /* !WRITE_INTERLACING */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* And write the whole thing, 7 times if interlacing it: */
|
||||||
|
for (; num_pass > 0; --num_pass)
|
||||||
|
png_write_rows(png_ptr, image, png_ptr->height);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free any memory used in png_ptr struct without freeing the struct itself. */
|
/* Free any memory used in png_ptr struct without freeing the struct itself. */
|
||||||
@ -1074,10 +1090,6 @@ png_write_destroy(png_structrp png_ptr)
|
|||||||
|
|
||||||
png_deflate_destroy(png_ptr);
|
png_deflate_destroy(png_ptr);
|
||||||
|
|
||||||
#ifdef PNG_WRITE_FILTER_SUPPORTED
|
|
||||||
png_free(png_ptr, png_ptr->row_buffer);
|
|
||||||
png_ptr->row_buffer = NULL;
|
|
||||||
#endif /* WRITE_FILTER */
|
|
||||||
#ifdef PNG_TRANSFORM_MECH_SUPPORTED
|
#ifdef PNG_TRANSFORM_MECH_SUPPORTED
|
||||||
png_transform_free(png_ptr, &png_ptr->transform_list);
|
png_transform_free(png_ptr, &png_ptr->transform_list);
|
||||||
#endif
|
#endif
|
||||||
|
2546
pngwutil.c
2546
pngwutil.c
File diff suppressed because it is too large
Load Diff
@ -930,20 +930,36 @@ option CONVERT_tIME requires WRITE_ANCILLARY_CHUNKS
|
|||||||
# png_set_filter interface allowing the application to select the filter
|
# png_set_filter interface allowing the application to select the filter
|
||||||
# used for each row.
|
# used for each row.
|
||||||
#
|
#
|
||||||
# SELECT_FILTER_HEURISTICALLY
|
# SELECT_FILTER
|
||||||
# Enables code to cause libpng to choose a filter from a set passed to
|
# Enables code to select between multiple filters on write. Without this
|
||||||
# png_set_filter. Without this code libpng just chooses the first filter in
|
# the 'first' (lowest numbered) filter will be selected an this typically
|
||||||
# the list if multiple are given.
|
# works out as PNG_FILTER_VALUE_NONE.
|
||||||
#
|
#
|
||||||
# SELECT_FILTER_METHODICALLY
|
# COMPRESSION_BUFFER_MAX
|
||||||
# Enables code to try all the filters in the list passed to png_set_filter
|
# WARNING: take care if you set this. This is the maximum amount of input
|
||||||
# and choose the one which results in the least number of compressed bytes
|
# data that the implementation of deflate can consume before it outputs a
|
||||||
# added by the current row.
|
# Huffman table for that data. I.e. before it commits to an encoding of the
|
||||||
|
# data it has read. This is used solely to implement a limit on the amount
|
||||||
|
# of image data buffering that occurs inside libpng before filter selection
|
||||||
|
# is done. Normally the limit is never reached because of the next setting,
|
||||||
|
# but this is a compile time limit and it is intended to prevent a potential
|
||||||
|
# DNS service as a result of an application setting the libpng equivalent of
|
||||||
|
# volume level 11 (read the wikipedia article on "Up to eleven").
|
||||||
|
#
|
||||||
|
# NOTE: the image of a black cat in a coal mine obviously requires this
|
||||||
|
# limit, but some more valid images can get very close; well over 8MByte.
|
||||||
|
#
|
||||||
|
# COMPRESSION_BUFFER_LIMIT
|
||||||
|
# This is the (overrideable) default for the amount of memory libpng will
|
||||||
|
# buffer before selecting a filter for a row. It is limited itself to
|
||||||
|
# COMPRESSION_BUFFER_MAX as values above that level make no change (see the
|
||||||
|
# previous paragraph.)
|
||||||
#
|
#
|
||||||
# See png.h for more description of these options.
|
# See png.h for more description of these options.
|
||||||
option WRITE_FILTER requires WRITE
|
option WRITE_FILTER requires WRITE
|
||||||
option SELECT_FILTER_HEURISTICALLY requires WRITE_FILTER enables SET_OPTION
|
option SELECT_FILTER requires WRITE_FILTER disabled
|
||||||
option SELECT_FILTER_METHODICALLY requires WRITE_FILTER enables SET_OPTION
|
setting COMPRESSION_BUFFER_MAX default 8453377
|
||||||
|
setting COMPRESSION_BUFFER_LIMIT default 8453377
|
||||||
|
|
||||||
# added at libpng-1.5.4
|
# added at libpng-1.5.4
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
/* libpng 1.7.0beta80 STANDARD API DEFINITION */
|
/* libpng 1.7.0beta80 STANDARD API DEFINITION */
|
||||||
|
|
||||||
/* pnglibconf.h - library build configuration */
|
/* pnglibconf.h - library build configuration */
|
||||||
|
|
||||||
/* Libpng version 1.7.0beta80, March 9, 2016 */
|
/* libpng version 1.7.0beta80, March 9, 2016 */
|
||||||
|
|
||||||
/* Copyright (c) 1998-2016 Glenn Randers-Pehrson */
|
/* Copyright (c) 1998-2016 Glenn Randers-Pehrson */
|
||||||
|
|
||||||
@ -100,8 +99,7 @@
|
|||||||
#define PNG_READ_tRNS_SUPPORTED
|
#define PNG_READ_tRNS_SUPPORTED
|
||||||
#define PNG_READ_zTXt_SUPPORTED
|
#define PNG_READ_zTXt_SUPPORTED
|
||||||
#define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
|
#define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED
|
||||||
#define PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED
|
/*#undef PNG_SELECT_FILTER_SUPPORTED*/
|
||||||
#define PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
|
|
||||||
#define PNG_SEQUENTIAL_READ_SUPPORTED
|
#define PNG_SEQUENTIAL_READ_SUPPORTED
|
||||||
#define PNG_SETJMP_SUPPORTED
|
#define PNG_SETJMP_SUPPORTED
|
||||||
#define PNG_SETTING_SUPPORTED
|
#define PNG_SETTING_SUPPORTED
|
||||||
@ -193,6 +191,8 @@
|
|||||||
/* settings */
|
/* settings */
|
||||||
#define PNG_ABORT { (abort()); }
|
#define PNG_ABORT { (abort()); }
|
||||||
#define PNG_API_RULE 0
|
#define PNG_API_RULE 0
|
||||||
|
#define PNG_COMPRESSION_BUFFER_LIMIT 8453377
|
||||||
|
#define PNG_COMPRESSION_BUFFER_MAX 8453377
|
||||||
#define PNG_DEFAULT_GAMMA_ACCURACY 665
|
#define PNG_DEFAULT_GAMMA_ACCURACY 665
|
||||||
#define PNG_DEFAULT_READ_MACROS 1
|
#define PNG_DEFAULT_READ_MACROS 1
|
||||||
#define PNG_GAMMA_THRESHOLD_FIXED 153
|
#define PNG_GAMMA_THRESHOLD_FIXED 153
|
||||||
|
Loading…
x
Reference in New Issue
Block a user