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:
John Bowler 2015-12-03 13:25:11 -08:00
parent 9fce04fcd6
commit 86499967c3
4 changed files with 181 additions and 143 deletions

View File

@ -959,12 +959,6 @@ PNG_INTERNAL_FUNCTION(void, png_zstream_error,(z_stream *zstream, int ret),
* 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) && \
!defined(PNG_FIXED_POINT_MACRO_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;
* 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
* is passed.)
* PNG_ROW_END set (this can be done in the same function call if the whole row
* is passed.) The following flags are used internally to control pass
* filtering and deflate:
*/
PNG_INTERNAL_FUNCTION(unsigned int, 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*/, int first_row_in_pass,
int last_pass_row, unsigned int filters_to_try/*from previous call*/,
int end_of_image),
enum
{
png_row_end =0x1U, /* This is the last block in the row */
png_pass_first_row =0x2U, /* This is the first row in a pass */
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);
#ifdef PNG_TRANSFORM_MECH_SUPPORTED

View File

@ -67,6 +67,11 @@
typedef struct png_compression_buffer *png_compression_bufferp;
#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
* 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_uint_32 zbuffer_len; /* Length of data in list */
unsigned int zbuffer_start; /* Bytes written from start */
unsigned int zbuffer_filters;/*Filters for this row */
# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
png_voidp zbuffer_select;
png_filter_selectp zbuffer_select;
# endif /* SELECT_FILTER_METHODICALLY */
# endif /* WRITE */
# ifdef PNG_READ_SUPPORTED

View File

@ -629,8 +629,8 @@ png_write_image(png_structrp png_ptr, png_bytepp image)
#if defined(PNG_WRITE_INTERLACING_SUPPORTED) ||\
defined(PNG_WRITE_TRANSFORMS_SUPPORTED)
static void
write_row_buffered(png_structrp png_ptr, png_const_bytep row,
int first_row_in_pass, int last_pass_row, int end_of_image,
write_row_buffered(png_structrp png_ptr,
png_const_bytep row, unsigned int row_info_flags,
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),
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 ?
png_ptr->width : PNG_PASS_COLS(png_ptr->width, pass);
png_uint_32 x;
unsigned int filters;
png_byte prev_pixels[4*2*2]; /* 2 pixels up to 4 2-byte channels each */
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
{
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)
max_pixels = (unsigned int)/*SAFE*/(width - x);
if (end_of_image && x + max_pixels >= width)
finish = 1;
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;
/* 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
@ -707,11 +705,10 @@ write_row_buffered(png_structrp png_ptr, png_const_bytep row,
# endif /* WRITE_TRANSFORMS */
/* 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
* initialized when 0 is 0 then preserved here for later blocks:
* maxpixels says if this is the final block in the row.
*/
filters = png_write_filter_row(png_ptr, prev_pixels, pixel_buffer.buffer,
x, max_pixels, first_row_in_pass, last_pass_row, filters, finish);
png_write_filter_row(png_ptr, prev_pixels, pixel_buffer.buffer, x,
max_pixels, row_info_flags);
}
}
#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
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: */
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 ?
png_ptr->width : PNG_PASS_COLS(png_ptr->width, pass);
png_uint_32 x;
unsigned int filters;
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
@ -847,10 +843,8 @@ write_row_unbuffered(png_structrp png_ptr, png_const_bytep row,
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)
{
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;
}
if (end_of_image && x + max_pixels >= width)
finish = 1;
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;
filters = png_write_filter_row(png_ptr, prev_pixels, row, x, max_pixels,
first_row_in_pass, last_pass_row, filters, finish);
png_write_filter_row(png_ptr, prev_pixels, row, x, max_pixels,
row_info_flags);
}
}
static void
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
if (png_ptr->transform_list != NULL)
write_row_buffered(png_ptr, row, first_row_in_pass, last_pass_row,
end_of_image, copy_row, png_ptr->row_input_pixel_depth);
write_row_buffered(png_ptr, row, row_info_flags,
copy_row, png_ptr->row_input_pixel_depth);
else
# 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
* the input data can be used unmodified.
*/
write_row_unbuffered(png_ptr, row, first_row_in_pass, last_pass_row,
end_of_image);
write_row_unbuffered(png_ptr, row, row_info_flags);
}
/* 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 int last_pass_row = row_number == png_ptr->height;
write_row_core(png_ptr, row, row_number == 1U, last_pass_row,
last_pass_row);
/* There is only one pass, so this is the last pass: */
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)
png_ptr->row_number = row_number;
@ -910,14 +907,17 @@ static void
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 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;
unsigned int pass = png_ptr->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,
last_pass_row && pass == PNG_LAST_PASS(png_ptr->width, png_ptr->height));
write_row_core(png_ptr, row,
(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)
png_ptr->row_number = row_number;
@ -950,8 +950,13 @@ interlace_row(png_structrp png_ptr, png_const_bytep row)
if (write_row)
{
const int last_pass_row =
PNG_LAST_PASS_ROW(row_number, pass, png_ptr->height);
const unsigned int row_info_flags =
(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)
{
@ -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;
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)
{
@ -975,22 +978,19 @@ interlace_row(png_structrp png_ptr, png_const_bytep row)
++B;
/*FALL THROUGH*/
case 1U: /* B will be 0 */
write_row_buffered(png_ptr, row,
row_number == PNG_PASS_START_ROW(pass), last_pass_row,
end_of_image, interlace_row_lbd, B);
write_row_buffered(png_ptr, row, row_info_flags,
interlace_row_lbd, B);
break;
default: /* Parameter is the pixel size in bytes */
write_row_buffered(png_ptr, row,
row_number == PNG_PASS_START_ROW(pass), last_pass_row,
end_of_image, interlace_row_byte, input_depth >> 3);
write_row_buffered(png_ptr, row, row_info_flags,
interlace_row_byte, input_depth >> 3);
break;
}
}
else /* pass 6; no interlacing required */
write_row_core(png_ptr, row, row_number == 1U, last_pass_row,
last_pass_row);
write_row_core(png_ptr, row, row_info_flags);
}
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");
/* Free any memory zlib uses */
if (png_ptr->zstream.state != NULL)
{
int ret = deflateEnd(&png_ptr->zstream);
png_deflate_destroy(png_ptr);
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
png_free(png_ptr, png_ptr->row_buffer);
png_ptr->row_buffer = NULL;

View File

@ -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. */
void /* PRIVATE */
static void
png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *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
* z_stream must have already been claimed (if required) and the compression
* buffer list pointer initialized to NULL or an existing list.
@ -2140,7 +2160,7 @@ png_write_flush(png_structrp png_ptr)
static void
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)
{
/* 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];
buffer[0] = filter;
buffer[0] = PNG_BYTE(filter);
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
filter_row(png_structrp png_ptr, png_const_bytep prev_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)
{
/* 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];
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);
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,
filters_to_try & PNG_FILTER_SUB ? filtered_row : NULL,
filters_to_try & PNG_FILTER_UP ? filtered_row : NULL,
filters_to_try & PNG_FILTER_AVG ? filtered_row : NULL,
filters_to_try & PNG_FILTER_PAETH ? filtered_row : NULL);
filter == PNG_FILTER_VALUE_SUB ? filtered_row : NULL,
filter == PNG_FILTER_VALUE_UP ? filtered_row : NULL,
filter == PNG_FILTER_VALUE_AVG ? filtered_row : NULL,
filter == PNG_FILTER_VALUE_PAETH ? filtered_row : NULL);
write_filtered_row(png_ptr, filtered_row, (row_bits+7U)>>3, filter,
end_of_image);
write_filtered_row(png_ptr, filtered_row, (row_bits+7U)>>3,
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
@ -2386,11 +2396,10 @@ filter_row(png_structrp png_ptr, png_const_bytep prev_row,
# define heuristic_option\
((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,
png_bytep prev_pixels, png_const_bytep unfiltered_row,
unsigned int row_bits, unsigned int bpp, unsigned int filters_to_try,
int end_of_image)
unsigned int row_bits, unsigned int bpp, int end_of_image)
{
const unsigned int row_bytes = (row_bits+7U) >> 3;
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.
*/
{
unsigned int filters_to_try = png_ptr->zbuffer_filters;
unsigned int filter_max = 257U;
png_byte best_filter, test_filter;
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;
}
/* Store the best filter found: */
png_ptr->zbuffer_filters = best_filter;
/* Calling write_unfiltered_rowbits is necessary here to deal with the
* 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
write_filtered_row(png_ptr, best_row, row_bytes, best_filter,
end_of_image);
return PNG_FILTER_MASK(best_filter);
}
}
#else /* !SELECT_FILTER_HEURISTICALLY */
@ -2462,11 +2473,10 @@ select_filters_methodically_init(png_structrp png_ptr)
affirm(png_ptr->zbuffer_select == NULL);
}
static int
static void
select_filter_methodically(png_structrp png_ptr, png_const_bytep prev_row,
png_bytep prev_pixels, png_const_bytep unfiltered_row,
unsigned int row_bits, unsigned int bpp, unsigned int filters_to_try,
int end_of_image)
unsigned int row_bits, unsigned int bpp, int end_of_row, int end_of_image)
{
const unsigned int row_bytes = (row_bits+7U) >> 3;
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,
PNG_FILTER_VALUE_LAST, end_of_image);
return filters_to_try;
PNG_UNUSED(end_of_row)
}
#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
* chosen filter.
*/
unsigned int /* PRIVATE */
void /* PRIVATE */
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*/, int first_row_in_pass, int last_pass_row,
unsigned int filters_to_try, int end_of_image)
unsigned int width/*pixels*/, unsigned int row_info_flags)
{
png_bytep prev_row = png_ptr->row_buffer;
const unsigned int bpp = png_ptr->row_output_pixel_depth;
const unsigned int row_bits = width * bpp;
unsigned int filters_to_try;
/* These invariants are expected from the caller: */
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);
/* 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
* 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
* the data.
*/
if (!first_row_in_pass)
if (!(row_info_flags & png_pass_first_row))
{
png_app_warning(png_ptr, "Previous row filters ignored");
/* 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
* 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);
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
}
@ -2588,9 +2597,27 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels,
if (heuristic_option == PNG_OPTION_OFF) /* don't use heuristics */
# endif /* SELECT_FILTER_HEURISTICALLY */
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 */
else if (prev_row != NULL)
else
{
if (prev_row != NULL)
{
/* Advance prev_row to the corresponding pixel above row[x], must use
* png_calc_rowbytes here otherwise the calculation using x might
@ -2600,47 +2627,54 @@ png_write_filter_row(png_structrp png_ptr, png_bytep prev_pixels,
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
* 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.
*/
if (filters_to_try == PNG_FILTER_NONE)
if (filters_to_try == PNG_FILTER_VALUE_NONE)
write_unfiltered_rowbits(png_ptr, unfiltered_row, row_bits,
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 */
filter_row(png_ptr, first_row_in_pass ? NULL : prev_row,
prev_pixels, unfiltered_row, row_bits, bpp, filters_to_try, x == 0,
end_of_image);
else
{
png_const_bytep prev =
(row_info_flags & png_pass_first_row) ? NULL : prev_row;
/* Is just one bit set in 'filters_to_try'? */
if (filters_to_try < PNG_FILTER_MASK(0))
filter_row(png_ptr, prev, prev_pixels, unfiltered_row, row_bits, bpp,
filters_to_try, x == 0, PNG_IDAT_END(row_info_flags));
# ifdef PNG_SELECT_FILTER_METHODICALLY_SUPPORTED
else if (png_ptr->zbuffer_select != NULL)
filters_to_try = select_filter_methodically(png_ptr,
first_row_in_pass ? NULL : prev_row, prev_pixels, unfiltered_row,
row_bits, bpp, filters_to_try, end_of_image);
select_filter_methodically(png_ptr, prev, prev_pixels,
unfiltered_row, row_bits, bpp,
(row_info_flags & png_row_end) != 0U,
PNG_IDAT_END(row_info_flags));
# endif /* SELECT_FILTER_METHODICALLY */
# ifdef PNG_SELECT_FILTER_HEURISTICALLY_SUPPORTED
/* The heuristic must select a single filter based on the first block of
* pixels:
/* The heuristic must select a single filter based on the first block
* of pixels; it updates zbuffer_filter to a single filter value.
*/
else
filters_to_try = select_filter_heuristically(png_ptr,
first_row_in_pass ? NULL : prev_row, prev_pixels, unfiltered_row,
row_bits, bpp, filters_to_try, end_of_image);
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
* 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.
*/
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);
return filters_to_try;
}
/* Allow the application to select one or more row filters to use. */