mirror of
https://git.code.sf.net/p/libpng/code.git
synced 2025-07-10 18:04:09 +02:00
Checkpoint for 'methodical' filter selection
This checkpoint is to allow the massive merge with the recent mainline libpng17 changes. Signed-off-by: John Bowler <jbowler@acm.org>
This commit is contained in:
parent
9fce04fcd6
commit
86499967c3
36
pngpriv.h
36
pngpriv.h
@ -959,12 +959,6 @@ PNG_INTERNAL_FUNCTION(void, png_zstream_error,(z_stream *zstream, int ret),
|
|||||||
* set before they return.
|
* set before they return.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef PNG_WRITE_SUPPORTED
|
|
||||||
PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr,
|
|
||||||
png_compression_bufferp *list),PNG_EMPTY);
|
|
||||||
/* Free the buffer list used by the compressed write code. */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
|
#if defined(PNG_FLOATING_POINT_SUPPORTED) && \
|
||||||
!defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \
|
!defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \
|
||||||
(defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \
|
(defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \
|
||||||
@ -1206,14 +1200,30 @@ PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr,
|
|||||||
*
|
*
|
||||||
* This may be called multiple times per row, but calls must be in 'x' order;
|
* This may be called multiple times per row, but calls must be in 'x' order;
|
||||||
* first a call with x 0 to mark the start of the row and, at the end, one with
|
* first a call with x 0 to mark the start of the row and, at the end, one with
|
||||||
* 'end_of_row' set (this can be done in the same function call if the whole row
|
* PNG_ROW_END set (this can be done in the same function call if the whole row
|
||||||
* is passed.)
|
* is passed.) The following flags are used internally to control pass
|
||||||
|
* filtering and deflate:
|
||||||
*/
|
*/
|
||||||
PNG_INTERNAL_FUNCTION(unsigned int, png_write_filter_row,
|
enum
|
||||||
(png_structrp png_ptr, png_bytep prev_pixels, png_const_bytep unfiltered_row,
|
{
|
||||||
png_uint_32 x, unsigned int width/*pixels*/, int first_row_in_pass,
|
png_row_end =0x1U, /* This is the last block in the row */
|
||||||
int last_pass_row, unsigned int filters_to_try/*from previous call*/,
|
png_pass_first_row =0x2U, /* This is the first row in a pass */
|
||||||
int end_of_image),
|
png_pass_last_row =0x4U, /* This is the last row in a pass */
|
||||||
|
png_pass_last =0x8U /* This is the last pass in the image */
|
||||||
|
|
||||||
|
/* A useful macro; return true if this is the last block of the last row in
|
||||||
|
* the image.
|
||||||
|
*/
|
||||||
|
# define PNG_IDAT_END(f) (((f) & ~png_pass_first_row) == \
|
||||||
|
(png_row_end+png_pass_last_row+png_pass_last))
|
||||||
|
};
|
||||||
|
PNG_INTERNAL_FUNCTION(void, png_write_filter_row, (png_structrp png_ptr,
|
||||||
|
png_bytep prev_pixels, png_const_bytep unfiltered_row, png_uint_32 x,
|
||||||
|
unsigned int width/*pixels*/, unsigned int row_info_flags),
|
||||||
|
PNG_EMPTY);
|
||||||
|
|
||||||
|
/* Release memory used by the deflate mechanism */
|
||||||
|
PNG_INTERNAL_FUNCTION(void, png_deflate_destroy, (png_structrp png_ptr),
|
||||||
PNG_EMPTY);
|
PNG_EMPTY);
|
||||||
|
|
||||||
#ifdef PNG_TRANSFORM_MECH_SUPPORTED
|
#ifdef PNG_TRANSFORM_MECH_SUPPORTED
|
||||||
|
|||||||
@ -67,6 +67,11 @@
|
|||||||
typedef struct png_compression_buffer *png_compression_bufferp;
|
typedef struct png_compression_buffer *png_compression_bufferp;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
|
||||||
|
/* Type of the data cache used when selecting filters methodicially */
|
||||||
|
typedef struct png_filter_select *png_filter_selectp;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* 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.
|
||||||
*
|
*
|
||||||
@ -751,8 +756,9 @@ struct png_struct_def
|
|||||||
png_compression_bufferp *zbuffer_end; /* 'next' field of current buffer */
|
png_compression_bufferp *zbuffer_end; /* 'next' field of current buffer */
|
||||||
png_uint_32 zbuffer_len; /* Length of data in list */
|
png_uint_32 zbuffer_len; /* Length of data in list */
|
||||||
unsigned int zbuffer_start; /* Bytes written from start */
|
unsigned int zbuffer_start; /* Bytes written from start */
|
||||||
|
unsigned int zbuffer_filters;/*Filters for this row */
|
||||||
# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
|
# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
|
||||||
png_voidp zbuffer_select;
|
png_filter_selectp zbuffer_select;
|
||||||
# endif /* SELECT_FILTER_METHODICALLY */
|
# endif /* SELECT_FILTER_METHODICALLY */
|
||||||
# endif /* WRITE */
|
# endif /* WRITE */
|
||||||
# ifdef PNG_READ_SUPPORTED
|
# ifdef PNG_READ_SUPPORTED
|
||||||
|
|||||||
100
pngwrite.c
100
pngwrite.c
@ -629,8 +629,8 @@ png_write_image(png_structrp png_ptr, png_bytepp image)
|
|||||||
#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
|
||||||
write_row_buffered(png_structrp png_ptr, png_const_bytep row,
|
write_row_buffered(png_structrp png_ptr,
|
||||||
int first_row_in_pass, int last_pass_row, int end_of_image,
|
png_const_bytep row, unsigned int row_info_flags,
|
||||||
void (*copy_fn)(png_const_structrp png_ptr, png_bytep row_buffer,
|
void (*copy_fn)(png_const_structrp png_ptr, png_bytep row_buffer,
|
||||||
png_const_bytep row, png_uint_32 x, unsigned int count, unsigned int p),
|
png_const_bytep row, png_uint_32 x, unsigned int count, unsigned int p),
|
||||||
unsigned int copy_parameter)
|
unsigned int copy_parameter)
|
||||||
@ -640,15 +640,12 @@ write_row_buffered(png_structrp png_ptr, png_const_bytep row,
|
|||||||
const png_uint_32 width = png_ptr->interlaced == PNG_INTERLACE_NONE ?
|
const png_uint_32 width = png_ptr->interlaced == PNG_INTERLACE_NONE ?
|
||||||
png_ptr->width : PNG_PASS_COLS(png_ptr->width, pass);
|
png_ptr->width : PNG_PASS_COLS(png_ptr->width, pass);
|
||||||
png_uint_32 x;
|
png_uint_32 x;
|
||||||
unsigned int filters;
|
|
||||||
png_byte prev_pixels[4*2*2]; /* 2 pixels up to 4 2-byte channels each */
|
png_byte prev_pixels[4*2*2]; /* 2 pixels up to 4 2-byte channels each */
|
||||||
|
|
||||||
memset(prev_pixels, 0U, sizeof prev_pixels);
|
memset(prev_pixels, 0U, sizeof prev_pixels);
|
||||||
|
|
||||||
for (x = 0U, filters = 0U; x < width; x += max_pixels)
|
for (x = 0U; x < width; x += max_pixels)
|
||||||
{
|
{
|
||||||
int finish = 0;
|
|
||||||
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
PNG_ROW_BUFFER_ALIGN_TYPE force_buffer_alignment;
|
PNG_ROW_BUFFER_ALIGN_TYPE force_buffer_alignment;
|
||||||
@ -658,8 +655,9 @@ write_row_buffered(png_structrp png_ptr, png_const_bytep row,
|
|||||||
if (max_pixels > width - x)
|
if (max_pixels > width - x)
|
||||||
max_pixels = (unsigned int)/*SAFE*/(width - x);
|
max_pixels = (unsigned int)/*SAFE*/(width - x);
|
||||||
|
|
||||||
if (end_of_image && x + max_pixels >= width)
|
debug((row_info_flags & png_row_end) == 0U); /* must be set here at end */
|
||||||
finish = 1;
|
if (x + max_pixels >= width)
|
||||||
|
row_info_flags |= png_row_end;
|
||||||
|
|
||||||
/* Copy a block of input pixels into the buffer, effecting the interlace
|
/* Copy a block of input pixels into the buffer, effecting the interlace
|
||||||
* on the way if required. The argument is the number of pixels in the
|
* on the way if required. The argument is the number of pixels in the
|
||||||
@ -707,11 +705,10 @@ write_row_buffered(png_structrp png_ptr, png_const_bytep row,
|
|||||||
# endif /* WRITE_TRANSFORMS */
|
# endif /* WRITE_TRANSFORMS */
|
||||||
|
|
||||||
/* Call png_write_filter_row to write this block of data, the test on
|
/* Call png_write_filter_row to write this block of data, the test on
|
||||||
* maxpixels says if this is the final block in the row, 'filters' is
|
* maxpixels says if this is the final block in the row.
|
||||||
* initialized when 0 is 0 then preserved here for later blocks:
|
|
||||||
*/
|
*/
|
||||||
filters = png_write_filter_row(png_ptr, prev_pixels, pixel_buffer.buffer,
|
png_write_filter_row(png_ptr, prev_pixels, pixel_buffer.buffer, x,
|
||||||
x, max_pixels, first_row_in_pass, last_pass_row, filters, finish);
|
max_pixels, row_info_flags);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif /* WRITE { INTERLACING || TRANSFORMS } */
|
#endif /* WRITE { INTERLACING || TRANSFORMS } */
|
||||||
@ -825,7 +822,7 @@ interlace_row_byte(png_const_structrp png_ptr, png_bytep dp, png_const_bytep sp,
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
write_row_unbuffered(png_structrp png_ptr, png_const_bytep row,
|
write_row_unbuffered(png_structrp png_ptr, png_const_bytep row,
|
||||||
int first_row_in_pass, int last_pass_row, int end_of_image)
|
unsigned int row_info_flags)
|
||||||
{
|
{
|
||||||
/* Split the row into blocks of the appropriate size: */
|
/* Split the row into blocks of the appropriate size: */
|
||||||
const unsigned int input_depth = png_ptr->row_input_pixel_depth;
|
const unsigned int input_depth = png_ptr->row_input_pixel_depth;
|
||||||
@ -835,7 +832,6 @@ write_row_unbuffered(png_structrp png_ptr, png_const_bytep row,
|
|||||||
const png_uint_32 width = png_ptr->interlaced == PNG_INTERLACE_NONE ?
|
const png_uint_32 width = png_ptr->interlaced == PNG_INTERLACE_NONE ?
|
||||||
png_ptr->width : PNG_PASS_COLS(png_ptr->width, pass);
|
png_ptr->width : PNG_PASS_COLS(png_ptr->width, pass);
|
||||||
png_uint_32 x;
|
png_uint_32 x;
|
||||||
unsigned int filters;
|
|
||||||
png_byte prev_pixels[4*2*2]; /* 2 pixels up to 4 2-byte channels each */
|
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
|
/* max_pixels is at most 16 bits, input_depth is at most 64, so the product
|
||||||
@ -847,10 +843,8 @@ write_row_unbuffered(png_structrp png_ptr, png_const_bytep row,
|
|||||||
|
|
||||||
memset(prev_pixels, 0U, sizeof prev_pixels);
|
memset(prev_pixels, 0U, sizeof prev_pixels);
|
||||||
|
|
||||||
for (x = 0U, filters = 0U; x < width; x += max_pixels, row += max_bytes)
|
for (x = 0U; x < width; x += max_pixels, row += max_bytes)
|
||||||
{
|
{
|
||||||
int finish = 0;
|
|
||||||
|
|
||||||
if (max_pixels > width - x)
|
if (max_pixels > width - x)
|
||||||
{
|
{
|
||||||
max_bytes = width - x;
|
max_bytes = width - x;
|
||||||
@ -858,22 +852,23 @@ write_row_unbuffered(png_structrp png_ptr, png_const_bytep row,
|
|||||||
max_bytes = (max_bytes * input_depth + 7U) >> 3;
|
max_bytes = (max_bytes * input_depth + 7U) >> 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end_of_image && x + max_pixels >= width)
|
debug((row_info_flags & png_row_end) == 0U); /* must be set here at end */
|
||||||
finish = 1;
|
if (x + max_pixels >= width)
|
||||||
|
row_info_flags |= png_row_end;
|
||||||
|
|
||||||
filters = png_write_filter_row(png_ptr, prev_pixels, row, x, max_pixels,
|
png_write_filter_row(png_ptr, prev_pixels, row, x, max_pixels,
|
||||||
first_row_in_pass, last_pass_row, filters, finish);
|
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,
|
||||||
int first_row_in_pass, int last_pass_row, int end_of_image)
|
unsigned int row_info_flags)
|
||||||
{
|
{
|
||||||
# ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
|
# ifdef PNG_WRITE_TRANSFORMS_SUPPORTED
|
||||||
if (png_ptr->transform_list != NULL)
|
if (png_ptr->transform_list != NULL)
|
||||||
write_row_buffered(png_ptr, row, first_row_in_pass, last_pass_row,
|
write_row_buffered(png_ptr, row, row_info_flags,
|
||||||
end_of_image, copy_row, png_ptr->row_input_pixel_depth);
|
copy_row, png_ptr->row_input_pixel_depth);
|
||||||
|
|
||||||
else
|
else
|
||||||
# endif /* WRITE_TRANSFORMS */
|
# endif /* WRITE_TRANSFORMS */
|
||||||
@ -881,8 +876,7 @@ 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, first_row_in_pass, last_pass_row,
|
write_row_unbuffered(png_ptr, row, row_info_flags);
|
||||||
end_of_image);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write a single non-interlaced row. */
|
/* Write a single non-interlaced row. */
|
||||||
@ -892,8 +886,11 @@ 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;
|
const int last_pass_row = row_number == png_ptr->height;
|
||||||
|
|
||||||
write_row_core(png_ptr, row, row_number == 1U, last_pass_row,
|
/* There is only one pass, so this is the last pass: */
|
||||||
last_pass_row);
|
write_row_core(png_ptr, row,
|
||||||
|
(row_number == 1U ? png_pass_first_row : 0U) |
|
||||||
|
(last_pass_row ? png_pass_last_row : 0U) |
|
||||||
|
png_pass_last);
|
||||||
|
|
||||||
if (!last_pass_row)
|
if (!last_pass_row)
|
||||||
png_ptr->row_number = row_number;
|
png_ptr->row_number = row_number;
|
||||||
@ -910,14 +907,17 @@ 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
|
/* 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 at the end.
|
* 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;
|
unsigned int pass = png_ptr->pass;
|
||||||
const int last_pass_row = row_number == PNG_PASS_ROWS(png_ptr->height, pass);
|
const int last_pass_row = row_number == PNG_PASS_ROWS(png_ptr->height, pass);
|
||||||
|
|
||||||
write_row_core(png_ptr, row, row_number == 1U, last_pass_row,
|
write_row_core(png_ptr, row,
|
||||||
last_pass_row && pass == PNG_LAST_PASS(png_ptr->width, png_ptr->height));
|
(row_number == 1U ? png_pass_first_row : 0U) |
|
||||||
|
(last_pass_row ? png_pass_last_row : 0U) |
|
||||||
|
(pass == PNG_LAST_PASS(png_ptr->width, png_ptr->height) ?
|
||||||
|
png_pass_last : 0U));
|
||||||
|
|
||||||
if (!last_pass_row)
|
if (!last_pass_row)
|
||||||
png_ptr->row_number = row_number;
|
png_ptr->row_number = row_number;
|
||||||
@ -950,8 +950,13 @@ interlace_row(png_structrp png_ptr, png_const_bytep row)
|
|||||||
|
|
||||||
if (write_row)
|
if (write_row)
|
||||||
{
|
{
|
||||||
const int last_pass_row =
|
const unsigned int row_info_flags =
|
||||||
PNG_LAST_PASS_ROW(row_number, pass, png_ptr->height);
|
(row_number == PNG_PASS_START_ROW(pass) ?
|
||||||
|
png_pass_first_row : 0U) |
|
||||||
|
(PNG_LAST_PASS_ROW(row_number, pass, png_ptr->height) ?
|
||||||
|
png_pass_last_row : 0U) |
|
||||||
|
(pass == PNG_LAST_PASS(png_ptr->width, png_ptr->height) ?
|
||||||
|
png_pass_last : 0U);
|
||||||
|
|
||||||
if (pass < 6)
|
if (pass < 6)
|
||||||
{
|
{
|
||||||
@ -963,8 +968,6 @@ interlace_row(png_structrp png_ptr, png_const_bytep row)
|
|||||||
*/
|
*/
|
||||||
const unsigned int input_depth = png_ptr->row_input_pixel_depth;
|
const unsigned int input_depth = png_ptr->row_input_pixel_depth;
|
||||||
unsigned int B = 0; /* log2(input_depth) */
|
unsigned int B = 0; /* log2(input_depth) */
|
||||||
const int end_of_image = last_pass_row &&
|
|
||||||
pass == PNG_LAST_PASS(png_ptr->width, png_ptr->height);
|
|
||||||
|
|
||||||
switch (input_depth)
|
switch (input_depth)
|
||||||
{
|
{
|
||||||
@ -975,22 +978,19 @@ interlace_row(png_structrp png_ptr, png_const_bytep row)
|
|||||||
++B;
|
++B;
|
||||||
/*FALL THROUGH*/
|
/*FALL THROUGH*/
|
||||||
case 1U: /* B will be 0 */
|
case 1U: /* B will be 0 */
|
||||||
write_row_buffered(png_ptr, row,
|
write_row_buffered(png_ptr, row, row_info_flags,
|
||||||
row_number == PNG_PASS_START_ROW(pass), last_pass_row,
|
interlace_row_lbd, B);
|
||||||
end_of_image, interlace_row_lbd, B);
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: /* Parameter is the pixel size in bytes */
|
default: /* Parameter is the pixel size in bytes */
|
||||||
write_row_buffered(png_ptr, row,
|
write_row_buffered(png_ptr, row, row_info_flags,
|
||||||
row_number == PNG_PASS_START_ROW(pass), last_pass_row,
|
interlace_row_byte, input_depth >> 3);
|
||||||
end_of_image, interlace_row_byte, input_depth >> 3);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else /* pass 6; no interlacing required */
|
else /* pass 6; no interlacing required */
|
||||||
write_row_core(png_ptr, row, row_number == 1U, last_pass_row,
|
write_row_core(png_ptr, row, row_info_flags);
|
||||||
last_pass_row);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (row_number+1U < png_ptr->height)
|
if (row_number+1U < png_ptr->height)
|
||||||
@ -1099,20 +1099,8 @@ png_write_destroy(png_structrp png_ptr)
|
|||||||
{
|
{
|
||||||
png_debug(1, "in png_write_destroy");
|
png_debug(1, "in png_write_destroy");
|
||||||
|
|
||||||
/* Free any memory zlib uses */
|
png_deflate_destroy(png_ptr);
|
||||||
if (png_ptr->zstream.state != NULL)
|
|
||||||
{
|
|
||||||
int ret = deflateEnd(&png_ptr->zstream);
|
|
||||||
|
|
||||||
if (ret != Z_OK)
|
|
||||||
{
|
|
||||||
png_zstream_error(&png_ptr->zstream, ret);
|
|
||||||
png_warning(png_ptr, png_ptr->zstream.msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Free our memory. png_free checks NULL for us. */
|
|
||||||
png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
|
|
||||||
#ifdef PNG_WRITE_FILTER_SUPPORTED
|
#ifdef PNG_WRITE_FILTER_SUPPORTED
|
||||||
png_free(png_ptr, png_ptr->row_buffer);
|
png_free(png_ptr, png_ptr->row_buffer);
|
||||||
png_ptr->row_buffer = NULL;
|
png_ptr->row_buffer = NULL;
|
||||||
|
|||||||
180
pngwutil.c
180
pngwutil.c
@ -458,7 +458,7 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Clean up (or trim) a linked list of compression buffers. */
|
/* Clean up (or trim) a linked list of compression buffers. */
|
||||||
void /* PRIVATE */
|
static void
|
||||||
png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp)
|
png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp)
|
||||||
{
|
{
|
||||||
png_compression_bufferp list = *listp;
|
png_compression_bufferp list = *listp;
|
||||||
@ -478,6 +478,26 @@ png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Release memory used by the deflate mechanism */
|
||||||
|
void /* PRIVATE */
|
||||||
|
png_deflate_destroy(png_structrp png_ptr)
|
||||||
|
{
|
||||||
|
/* Free any memory zlib uses */
|
||||||
|
if (png_ptr->zstream.state != NULL)
|
||||||
|
{
|
||||||
|
int ret = deflateEnd(&png_ptr->zstream);
|
||||||
|
|
||||||
|
if (ret != Z_OK)
|
||||||
|
{
|
||||||
|
png_zstream_error(&png_ptr->zstream, ret);
|
||||||
|
png_warning(png_ptr, png_ptr->zstream.msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Free our memory. png_free checks NULL for us. */
|
||||||
|
png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
|
||||||
|
}
|
||||||
|
|
||||||
/* Compress the given data given a compression buffer list. The passed in
|
/* Compress the given data given a compression buffer list. The passed in
|
||||||
* z_stream must have already been claimed (if required) and the compression
|
* z_stream must have already been claimed (if required) and the compression
|
||||||
* buffer list pointer initialized to NULL or an existing list.
|
* buffer list pointer initialized to NULL or an existing list.
|
||||||
@ -2140,7 +2160,7 @@ png_write_flush(png_structrp png_ptr)
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
write_filtered_row(png_structrp png_ptr, png_const_voidp filtered_row,
|
write_filtered_row(png_structrp png_ptr, png_const_voidp filtered_row,
|
||||||
unsigned int row_bytes, png_byte filter /*if at start of row*/,
|
unsigned int row_bytes, unsigned int filter /*if at start of row*/,
|
||||||
int end_of_image)
|
int end_of_image)
|
||||||
{
|
{
|
||||||
/* This handles writing a row that has been filtered, or did not need to be
|
/* This handles writing a row that has been filtered, or did not need to be
|
||||||
@ -2155,7 +2175,7 @@ write_filtered_row(png_structrp png_ptr, png_const_voidp filtered_row,
|
|||||||
{
|
{
|
||||||
png_byte buffer[1];
|
png_byte buffer[1];
|
||||||
|
|
||||||
buffer[0] = filter;
|
buffer[0] = PNG_BYTE(filter);
|
||||||
png_compress_IDAT(png_ptr, buffer, 1U/*len*/, Z_NO_FLUSH);
|
png_compress_IDAT(png_ptr, buffer, 1U/*len*/, Z_NO_FLUSH);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2341,35 +2361,25 @@ filter_block(png_const_bytep prev_row, png_bytep prev_pixels,
|
|||||||
static void
|
static void
|
||||||
filter_row(png_structrp png_ptr, png_const_bytep prev_row,
|
filter_row(png_structrp png_ptr, png_const_bytep prev_row,
|
||||||
png_bytep prev_pixels, png_const_bytep unfiltered_row,
|
png_bytep prev_pixels, png_const_bytep unfiltered_row,
|
||||||
unsigned int row_bits, unsigned int bpp, unsigned int filters_to_try,
|
unsigned int row_bits, unsigned int bpp, unsigned int filter,
|
||||||
int start_of_row, int end_of_image)
|
int start_of_row, int end_of_image)
|
||||||
{
|
{
|
||||||
/* filters_to_try identifies a single filter and it is not PNG_FILTER_NONE.
|
/* filters_to_try identifies a single filter and it is not PNG_FILTER_NONE.
|
||||||
*/
|
*/
|
||||||
png_byte filter = PNG_FILTER_VALUE_LAST /* not at start */;
|
|
||||||
png_byte filtered_row[PNG_ROW_BUFFER_SIZE];
|
png_byte filtered_row[PNG_ROW_BUFFER_SIZE];
|
||||||
|
|
||||||
affirm((row_bits+7U) >> 3 <= PNG_ROW_BUFFER_SIZE);
|
affirm((row_bits+7U) >> 3 <= PNG_ROW_BUFFER_SIZE &&
|
||||||
|
filter >= PNG_FILTER_VALUE_SUB && filter <= PNG_FILTER_VALUE_PAETH);
|
||||||
debug((row_bits % bpp) == 0U);
|
debug((row_bits % bpp) == 0U);
|
||||||
|
|
||||||
if (start_of_row) switch (filters_to_try)
|
|
||||||
{
|
|
||||||
case PNG_FILTER_SUB: filter = PNG_FILTER_VALUE_SUB; break;
|
|
||||||
case PNG_FILTER_UP: filter = PNG_FILTER_VALUE_UP; break;
|
|
||||||
case PNG_FILTER_AVG: filter = PNG_FILTER_VALUE_AVG; break;
|
|
||||||
case PNG_FILTER_PAETH: filter = PNG_FILTER_VALUE_PAETH; break;
|
|
||||||
default:
|
|
||||||
impossible("filter list");
|
|
||||||
}
|
|
||||||
|
|
||||||
filter_block(prev_row, prev_pixels, unfiltered_row, row_bits, bpp,
|
filter_block(prev_row, prev_pixels, unfiltered_row, row_bits, bpp,
|
||||||
filters_to_try & PNG_FILTER_SUB ? filtered_row : NULL,
|
filter == PNG_FILTER_VALUE_SUB ? filtered_row : NULL,
|
||||||
filters_to_try & PNG_FILTER_UP ? filtered_row : NULL,
|
filter == PNG_FILTER_VALUE_UP ? filtered_row : NULL,
|
||||||
filters_to_try & PNG_FILTER_AVG ? filtered_row : NULL,
|
filter == PNG_FILTER_VALUE_AVG ? filtered_row : NULL,
|
||||||
filters_to_try & PNG_FILTER_PAETH ? filtered_row : NULL);
|
filter == PNG_FILTER_VALUE_PAETH ? filtered_row : NULL);
|
||||||
|
|
||||||
write_filtered_row(png_ptr, filtered_row, (row_bits+7U)>>3, filter,
|
write_filtered_row(png_ptr, filtered_row, (row_bits+7U)>>3,
|
||||||
end_of_image);
|
start_of_row ? filter : PNG_FILTER_VALUE_LAST, end_of_image);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* These two #defines simplify writing code that depends on one or the other of
|
/* These two #defines simplify writing code that depends on one or the other of
|
||||||
@ -2386,11 +2396,10 @@ filter_row(png_structrp png_ptr, png_const_bytep prev_row,
|
|||||||
# define heuristic_option\
|
# define heuristic_option\
|
||||||
((png_ptr->options >> PNG_SELECT_FILTER_HEURISTICALLY) & 3U)
|
((png_ptr->options >> PNG_SELECT_FILTER_HEURISTICALLY) & 3U)
|
||||||
|
|
||||||
static unsigned int
|
static void
|
||||||
select_filter_heuristically(png_structrp png_ptr, png_const_bytep prev_row,
|
select_filter_heuristically(png_structrp png_ptr, png_const_bytep prev_row,
|
||||||
png_bytep prev_pixels, png_const_bytep unfiltered_row,
|
png_bytep prev_pixels, png_const_bytep unfiltered_row,
|
||||||
unsigned int row_bits, unsigned int bpp, unsigned int filters_to_try,
|
unsigned int row_bits, unsigned int bpp, int end_of_image)
|
||||||
int end_of_image)
|
|
||||||
{
|
{
|
||||||
const unsigned int row_bytes = (row_bits+7U) >> 3;
|
const unsigned int row_bytes = (row_bits+7U) >> 3;
|
||||||
png_byte test_buffers[4][PNG_ROW_BUFFER_SIZE]; /* for each filter */
|
png_byte test_buffers[4][PNG_ROW_BUFFER_SIZE]; /* for each filter */
|
||||||
@ -2411,6 +2420,7 @@ select_filter_heuristically(png_structrp png_ptr, png_const_bytep prev_row,
|
|||||||
* generated or we expect a count of average 8 per code.
|
* generated or we expect a count of average 8 per code.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
|
unsigned int filters_to_try = png_ptr->zbuffer_filters;
|
||||||
unsigned int filter_max = 257U;
|
unsigned int filter_max = 257U;
|
||||||
png_byte best_filter, test_filter;
|
png_byte best_filter, test_filter;
|
||||||
png_const_bytep best_row, test_row;
|
png_const_bytep best_row, test_row;
|
||||||
@ -2437,6 +2447,9 @@ select_filter_heuristically(png_structrp png_ptr, png_const_bytep prev_row,
|
|||||||
filter_max = count, best_filter = test_filter, best_row = test_row;
|
filter_max = count, best_filter = test_filter, best_row = test_row;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Store the best filter found: */
|
||||||
|
png_ptr->zbuffer_filters = best_filter;
|
||||||
|
|
||||||
/* Calling write_unfiltered_rowbits is necessary here to deal with the
|
/* Calling write_unfiltered_rowbits is necessary here to deal with the
|
||||||
* clearly of a partial byte at the end.
|
* clearly of a partial byte at the end.
|
||||||
*/
|
*/
|
||||||
@ -2447,8 +2460,6 @@ select_filter_heuristically(png_structrp png_ptr, png_const_bytep prev_row,
|
|||||||
else
|
else
|
||||||
write_filtered_row(png_ptr, best_row, row_bytes, best_filter,
|
write_filtered_row(png_ptr, best_row, row_bytes, best_filter,
|
||||||
end_of_image);
|
end_of_image);
|
||||||
|
|
||||||
return PNG_FILTER_MASK(best_filter);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#else /* !SELECT_FILTER_HEURISTICALLY */
|
#else /* !SELECT_FILTER_HEURISTICALLY */
|
||||||
@ -2462,11 +2473,10 @@ select_filters_methodically_init(png_structrp png_ptr)
|
|||||||
affirm(png_ptr->zbuffer_select == NULL);
|
affirm(png_ptr->zbuffer_select == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static void
|
||||||
select_filter_methodically(png_structrp png_ptr, png_const_bytep prev_row,
|
select_filter_methodically(png_structrp png_ptr, png_const_bytep prev_row,
|
||||||
png_bytep prev_pixels, png_const_bytep unfiltered_row,
|
png_bytep prev_pixels, png_const_bytep unfiltered_row,
|
||||||
unsigned int row_bits, unsigned int bpp, unsigned int filters_to_try,
|
unsigned int row_bits, unsigned int bpp, int end_of_row, int end_of_image)
|
||||||
int end_of_image)
|
|
||||||
{
|
{
|
||||||
const unsigned int row_bytes = (row_bits+7U) >> 3;
|
const unsigned int row_bytes = (row_bits+7U) >> 3;
|
||||||
png_byte test_buffers[4][PNG_ROW_BUFFER_SIZE]; /* for each filter */
|
png_byte test_buffers[4][PNG_ROW_BUFFER_SIZE]; /* for each filter */
|
||||||
@ -2482,8 +2492,7 @@ select_filter_methodically(png_structrp png_ptr, png_const_bytep prev_row,
|
|||||||
|
|
||||||
write_unfiltered_rowbits(png_ptr, unfiltered_row, row_bits,
|
write_unfiltered_rowbits(png_ptr, unfiltered_row, row_bits,
|
||||||
PNG_FILTER_VALUE_LAST, end_of_image);
|
PNG_FILTER_VALUE_LAST, end_of_image);
|
||||||
|
PNG_UNUSED(end_of_row)
|
||||||
return filters_to_try;
|
|
||||||
}
|
}
|
||||||
#endif /* SELECT_FILTER_METHODICALLY */
|
#endif /* SELECT_FILTER_METHODICALLY */
|
||||||
|
|
||||||
@ -2491,15 +2500,15 @@ select_filter_methodically(png_structrp png_ptr, png_const_bytep prev_row,
|
|||||||
* been specified by the application, and then writes the row out with the
|
* been specified by the application, and then writes the row out with the
|
||||||
* chosen filter.
|
* chosen filter.
|
||||||
*/
|
*/
|
||||||
unsigned int /* PRIVATE */
|
void /* PRIVATE */
|
||||||
png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels,
|
png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels,
|
||||||
png_const_bytep unfiltered_row, png_uint_32 x,
|
png_const_bytep unfiltered_row, png_uint_32 x,
|
||||||
unsigned int width/*pixels*/, int first_row_in_pass, int last_pass_row,
|
unsigned int width/*pixels*/, unsigned int row_info_flags)
|
||||||
unsigned int filters_to_try, int end_of_image)
|
|
||||||
{
|
{
|
||||||
png_bytep prev_row = png_ptr->row_buffer;
|
png_bytep prev_row = png_ptr->row_buffer;
|
||||||
const unsigned int bpp = png_ptr->row_output_pixel_depth;
|
const unsigned int bpp = png_ptr->row_output_pixel_depth;
|
||||||
const unsigned int row_bits = width * bpp;
|
const unsigned int row_bits = width * bpp;
|
||||||
|
unsigned int filters_to_try;
|
||||||
|
|
||||||
/* These invariants are expected from the caller: */
|
/* These invariants are expected from the caller: */
|
||||||
affirm(width < 65536U && bpp <= 64U && width < 65536U/bpp &&
|
affirm(width < 65536U && bpp <= 64U && width < 65536U/bpp &&
|
||||||
@ -2519,7 +2528,7 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels,
|
|||||||
PNG_ALL_FILTERS : PNG_NO_FILTERS);
|
PNG_ALL_FILTERS : PNG_NO_FILTERS);
|
||||||
|
|
||||||
/* Now work out the filters to try for this row: */
|
/* Now work out the filters to try for this row: */
|
||||||
filters_to_try = png_ptr->filter_mask; /* else caller must preserve */
|
filters_to_try = png_ptr->filter_mask;
|
||||||
|
|
||||||
/* If this has a previous row filter in the set to try ensure the row
|
/* If this has a previous row filter in the set to try ensure the row
|
||||||
* buffer exists and ensure it is empty when first allocated and at
|
* buffer exists and ensure it is empty when first allocated and at
|
||||||
@ -2541,7 +2550,7 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels,
|
|||||||
* app warning and disable the filters that would have required
|
* app warning and disable the filters that would have required
|
||||||
* the data.
|
* the data.
|
||||||
*/
|
*/
|
||||||
if (!first_row_in_pass)
|
if (!(row_info_flags & png_pass_first_row))
|
||||||
{
|
{
|
||||||
png_app_warning(png_ptr, "Previous row filters ignored");
|
png_app_warning(png_ptr, "Previous row filters ignored");
|
||||||
/* And always turn off the filters, to prevent using
|
/* And always turn off the filters, to prevent using
|
||||||
@ -2556,7 +2565,7 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (first_row_in_pass)
|
if ((row_info_flags & png_pass_first_row) != 0U)
|
||||||
{
|
{
|
||||||
/* On the first row UP and NONE are the same, PAETH and SUB are the
|
/* On the first row UP and NONE are the same, PAETH and SUB are the
|
||||||
* same, so if both members of a pair occur together eliminate the one
|
* same, so if both members of a pair occur together eliminate the one
|
||||||
@ -2569,7 +2578,7 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels,
|
|||||||
filters_to_try &= PNG_BIC_MASK(PNG_FILTER_UP);
|
filters_to_try &= PNG_BIC_MASK(PNG_FILTER_UP);
|
||||||
|
|
||||||
if (match(PNG_FILTER_SUB+PNG_FILTER_PAETH))
|
if (match(PNG_FILTER_SUB+PNG_FILTER_PAETH))
|
||||||
filters_to_try &= PNG_BIC_MASK(PNG_FILTER_UP);
|
filters_to_try &= PNG_BIC_MASK(PNG_FILTER_PAETH);
|
||||||
# undef match
|
# undef match
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2588,59 +2597,84 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels,
|
|||||||
if (heuristic_option == PNG_OPTION_OFF) /* don't use heuristics */
|
if (heuristic_option == PNG_OPTION_OFF) /* don't use heuristics */
|
||||||
# endif /* SELECT_FILTER_HEURISTICALLY */
|
# endif /* SELECT_FILTER_HEURISTICALLY */
|
||||||
filters_to_try &= -filters_to_try;
|
filters_to_try &= -filters_to_try;
|
||||||
|
|
||||||
|
/* If there is just one bit set in filters_to_try convert it to the filter
|
||||||
|
* value and store that.
|
||||||
|
*/
|
||||||
|
if ((filters_to_try & (filters_to_try-1U)) == 0U) switch (filters_to_try)
|
||||||
|
{
|
||||||
|
case PNG_FILTER_NONE: filters_to_try = PNG_FILTER_VALUE_NONE; break;
|
||||||
|
case PNG_FILTER_SUB: filters_to_try = PNG_FILTER_VALUE_SUB; break;
|
||||||
|
case PNG_FILTER_UP: filters_to_try = PNG_FILTER_VALUE_UP; break;
|
||||||
|
case PNG_FILTER_AVG: filters_to_try = PNG_FILTER_VALUE_AVG; break;
|
||||||
|
case PNG_FILTER_PAETH: filters_to_try = PNG_FILTER_VALUE_PAETH; break;
|
||||||
|
default:
|
||||||
|
impossible("bad filter mask");
|
||||||
|
}
|
||||||
|
|
||||||
|
png_ptr->zbuffer_filters = filters_to_try;
|
||||||
} /* start of row */
|
} /* start of row */
|
||||||
|
|
||||||
else if (prev_row != NULL)
|
else
|
||||||
{
|
{
|
||||||
/* Advance prev_row to the corresponding pixel above row[x], must use
|
if (prev_row != NULL)
|
||||||
* png_calc_rowbytes here otherwise the calculation using x might
|
{
|
||||||
* overflow.
|
/* Advance prev_row to the corresponding pixel above row[x], must use
|
||||||
*/
|
* png_calc_rowbytes here otherwise the calculation using x might
|
||||||
debug(((x * bpp) & 7U) == 0U);
|
* overflow.
|
||||||
prev_row += png_calc_rowbytes(png_ptr, bpp, x);
|
*/
|
||||||
|
debug(((x * bpp) & 7U) == 0U);
|
||||||
|
prev_row += png_calc_rowbytes(png_ptr, bpp, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
filters_to_try = png_ptr->zbuffer_filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Now choose the correct filter implementation according to the number of
|
/* Now choose the correct filter implementation according to the number of
|
||||||
* filters in the filters_to_try list. The prev_row parameter is made NULL
|
* filters in the filters_to_try list. The prev_row parameter is made NULL
|
||||||
* on the first row because it is uninitialized at that point.
|
* on the first row because it is uninitialized at that point.
|
||||||
*/
|
*/
|
||||||
if (filters_to_try == PNG_FILTER_NONE)
|
if (filters_to_try == PNG_FILTER_VALUE_NONE)
|
||||||
write_unfiltered_rowbits(png_ptr, unfiltered_row, row_bits,
|
write_unfiltered_rowbits(png_ptr, unfiltered_row, row_bits,
|
||||||
x == 0 ? PNG_FILTER_VALUE_NONE : PNG_FILTER_VALUE_LAST,
|
x == 0 ? PNG_FILTER_VALUE_NONE : PNG_FILTER_VALUE_LAST,
|
||||||
end_of_image);
|
PNG_IDAT_END(row_info_flags));
|
||||||
|
|
||||||
else if ((filters_to_try & -filters_to_try) == filters_to_try) /* 1 filter */
|
else
|
||||||
filter_row(png_ptr, first_row_in_pass ? NULL : prev_row,
|
{
|
||||||
prev_pixels, unfiltered_row, row_bits, bpp, filters_to_try, x == 0,
|
png_const_bytep prev =
|
||||||
end_of_image);
|
(row_info_flags & png_pass_first_row) ? NULL : prev_row;
|
||||||
|
|
||||||
# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
|
/* Is just one bit set in 'filters_to_try'? */
|
||||||
else if (png_ptr->zbuffer_select != NULL)
|
if (filters_to_try < PNG_FILTER_MASK(0))
|
||||||
filters_to_try = select_filter_methodically(png_ptr,
|
filter_row(png_ptr, prev, prev_pixels, unfiltered_row, row_bits, bpp,
|
||||||
first_row_in_pass ? NULL : prev_row, prev_pixels, unfiltered_row,
|
filters_to_try, x == 0, PNG_IDAT_END(row_info_flags));
|
||||||
row_bits, bpp, filters_to_try, end_of_image);
|
|
||||||
# endif /* SELECT_FILTER_METHODICALLY */
|
# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
|
||||||
# ifdef PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED
|
else if (png_ptr->zbuffer_select != NULL)
|
||||||
/* The heuristic must select a single filter based on the first block of
|
select_filter_methodically(png_ptr, prev, prev_pixels,
|
||||||
* pixels:
|
unfiltered_row, row_bits, bpp,
|
||||||
*/
|
(row_info_flags & png_row_end) != 0U,
|
||||||
else
|
PNG_IDAT_END(row_info_flags));
|
||||||
filters_to_try = select_filter_heuristically(png_ptr,
|
# endif /* SELECT_FILTER_METHODICALLY */
|
||||||
first_row_in_pass ? NULL : prev_row, prev_pixels, unfiltered_row,
|
# ifdef PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED
|
||||||
row_bits, bpp, filters_to_try, end_of_image);
|
/* The heuristic must select a single filter based on the first block
|
||||||
# else /* !SELECT_FILTER_HEURISTICALLY */
|
* of pixels; it updates zbuffer_filter to a single filter value.
|
||||||
else
|
*/
|
||||||
impossible("bad filter select logic");
|
else
|
||||||
# endif /* !SELECT_FILTER_HEURISTICALLY */
|
select_filter_heuristically(png_ptr, prev, prev_pixels,
|
||||||
|
unfiltered_row, row_bits, bpp, PNG_IDAT_END(row_info_flags));
|
||||||
|
# else /* !SELECT_FILTER_HEURISTICALLY */
|
||||||
|
else
|
||||||
|
impossible("bad filter select logic");
|
||||||
|
# endif /* !SELECT_FILTER_HEURISTICALLY */
|
||||||
|
}
|
||||||
|
|
||||||
/* Copy the current row into the previous row buffer, if available, unless
|
/* Copy the current row into the previous row buffer, if available, unless
|
||||||
* this is the last row in the pass, when there is no point. Note that
|
* this is the last row in the pass, when there is no point. Note that
|
||||||
* prev_row may have garbage in a partial byte at the end.
|
* prev_row may have garbage in a partial byte at the end.
|
||||||
*/
|
*/
|
||||||
if (prev_row != NULL && !last_pass_row)
|
if (prev_row != NULL && !(row_info_flags & png_pass_last_row))
|
||||||
memcpy(prev_row, unfiltered_row, (row_bits + 7U) >> 3);
|
memcpy(prev_row, unfiltered_row, (row_bits + 7U) >> 3);
|
||||||
|
|
||||||
return filters_to_try;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Allow the application to select one or more row filters to use. */
|
/* Allow the application to select one or more row filters to use. */
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user