diff options
Diffstat (limited to 'plugins/AdvaImg/src/LibPNG/pngwutil.c')
-rw-r--r-- | plugins/AdvaImg/src/LibPNG/pngwutil.c | 1155 |
1 files changed, 442 insertions, 713 deletions
diff --git a/plugins/AdvaImg/src/LibPNG/pngwutil.c b/plugins/AdvaImg/src/LibPNG/pngwutil.c index 409334d064..21f489b347 100644 --- a/plugins/AdvaImg/src/LibPNG/pngwutil.c +++ b/plugins/AdvaImg/src/LibPNG/pngwutil.c @@ -1,8 +1,8 @@ /* pngwutil.c - utilities to write a PNG file
*
- * Last changed in libpng 1.6.17 [March 26, 2015]
- * Copyright (c) 1998-2015 Glenn Randers-Pehrson
+ * Last changed in libpng 1.6.26 [October 20, 2016]
+ * Copyright (c) 1998-2002,2004,2006-2016 Glenn Randers-Pehrson
* (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
* (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
*
@@ -23,10 +23,10 @@ void PNGAPI
png_save_uint_32(png_bytep buf, png_uint_32 i)
{
- buf[0] = (png_byte)(i >> 24);
- buf[1] = (png_byte)(i >> 16);
- buf[2] = (png_byte)(i >> 8);
- buf[3] = (png_byte)(i );
+ buf[0] = (png_byte)((i >> 24) & 0xffU);
+ buf[1] = (png_byte)((i >> 16) & 0xffU);
+ buf[2] = (png_byte)((i >> 8) & 0xffU);
+ buf[3] = (png_byte)( i & 0xffU);
}
/* Place a 16-bit number into a buffer in PNG byte order.
@@ -36,8 +36,8 @@ png_save_uint_32(png_bytep buf, png_uint_32 i) void PNGAPI
png_save_uint_16(png_bytep buf, unsigned int i)
{
- buf[0] = (png_byte)(i >> 8);
- buf[1] = (png_byte)(i );
+ buf[0] = (png_byte)((i >> 8) & 0xffU);
+ buf[1] = (png_byte)( i & 0xffU);
}
#endif
@@ -59,7 +59,7 @@ png_write_sig(png_structrp png_ptr) /* Write the rest of the 8 byte signature */
png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes],
- (png_size_t)(8 - png_ptr->sig_bytes));
+ (png_size_t)(8 - png_ptr->sig_bytes));
if (png_ptr->sig_bytes < 3)
png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE;
@@ -174,12 +174,12 @@ png_write_chunk_end(png_structrp png_ptr) */
static void
png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name,
- png_const_bytep data, png_size_t length)
+ png_const_bytep data, png_size_t length)
{
if (png_ptr == NULL)
return;
- /* On 64 bit architectures 'length' may not fit in a png_uint_32. */
+ /* On 64-bit architectures 'length' may not fit in a png_uint_32. */
if (length > PNG_UINT_31_MAX)
png_error(png_ptr, "length exceeds PNG maximum");
@@ -191,10 +191,10 @@ png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name, /* This is the API that calls the internal function above. */
void PNGAPI
png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string,
- png_const_bytep data, png_size_t length)
+ png_const_bytep data, png_size_t length)
{
png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data,
- length);
+ length);
}
/* This is used below to find the size of an image to pass to png_deflate_claim,
@@ -291,7 +291,7 @@ optimize_cmf(png_bytep data, png_alloc_size_t data_size) /* Initialize the compressor for the appropriate type of compression. */
static int
png_deflate_claim(png_structrp png_ptr, png_uint_32 owner,
- png_alloc_size_t data_size)
+ png_alloc_size_t data_size)
{
if (png_ptr->zowner != 0)
{
@@ -308,7 +308,7 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, */
(void)png_safecat(msg, (sizeof msg), 10, " using zstream");
#endif
-#if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC
+#if PNG_RELEASE_BUILD
png_warning(png_ptr, msg);
/* Attempt sane error recovery */
@@ -408,7 +408,7 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, png_ptr->zstream.avail_out = 0;
/* Now initialize if required, setting the new parameters, otherwise just
- * to a simple reset to the previous parameters.
+ * do a simple reset to the previous parameters.
*/
if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0)
ret = deflateReset(&png_ptr->zstream);
@@ -416,7 +416,7 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, else
{
ret = deflateInit2(&png_ptr->zstream, level, method, windowBits,
- memLevel, strategy);
+ memLevel, strategy);
if (ret == Z_OK)
png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED;
@@ -477,7 +477,7 @@ typedef struct static void
png_text_compress_init(compression_state *comp, png_const_bytep input,
- png_alloc_size_t input_len)
+ png_alloc_size_t input_len)
{
comp->input = input;
comp->input_len = input_len;
@@ -487,7 +487,7 @@ png_text_compress_init(compression_state *comp, png_const_bytep input, /* Compress the data in the compression state input */
static int
png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name,
- compression_state *comp, png_uint_32 prefix_len)
+ compression_state *comp, png_uint_32 prefix_len)
{
int ret;
@@ -579,7 +579,7 @@ png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, /* Compress the data */
ret = deflate(&png_ptr->zstream,
- input_len > 0 ? Z_NO_FLUSH : Z_FINISH);
+ input_len > 0 ? Z_NO_FLUSH : Z_FINISH);
/* Claw back input data that was not consumed (because avail_in is
* reset above every time round the loop).
@@ -665,90 +665,6 @@ png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp) }
#endif /* WRITE_COMPRESSED_TEXT */
-#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \
- defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED)
-/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
- * and if invalid, correct the keyword rather than discarding the entire
- * chunk. The PNG 1.0 specification requires keywords 1-79 characters in
- * length, forbids leading or trailing whitespace, multiple internal spaces,
- * and the non-break space (0x80) from ISO 8859-1. Returns keyword length.
- *
- * The 'new_key' buffer must be 80 characters in size (for the keyword plus a
- * trailing '\0'). If this routine returns 0 then there was no keyword, or a
- * valid one could not be generated, and the caller must png_error.
- */
-static png_uint_32
-png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key)
-{
- png_const_charp orig_key = key;
- png_uint_32 key_len = 0;
- int bad_character = 0;
- int space = 1;
-
- png_debug(1, "in png_check_keyword");
-
- if (key == NULL)
- {
- *new_key = 0;
- return 0;
- }
-
- while (*key && key_len < 79)
- {
- png_byte ch = (png_byte)*key++;
-
- if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/))
- *new_key++ = ch, ++key_len, space = 0;
-
- else if (space == 0)
- {
- /* A space or an invalid character when one wasn't seen immediately
- * before; output just a space.
- */
- *new_key++ = 32, ++key_len, space = 1;
-
- /* If the character was not a space then it is invalid. */
- if (ch != 32)
- bad_character = ch;
- }
-
- else if (bad_character == 0)
- bad_character = ch; /* just skip it, record the first error */
- }
-
- if (key_len > 0 && space != 0) /* trailing space */
- {
- --key_len, --new_key;
- if (bad_character == 0)
- bad_character = 32;
- }
-
- /* Terminate the keyword */
- *new_key = 0;
-
- if (key_len == 0)
- return 0;
-
-#ifdef PNG_WARNINGS_SUPPORTED
- /* Try to only output one warning per keyword: */
- if (*key != 0) /* keyword too long */
- png_warning(png_ptr, "keyword truncated");
-
- else if (bad_character != 0)
- {
- PNG_WARNING_PARAMETERS(p)
-
- png_warning_parameter(p, 1, orig_key);
- png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character);
-
- png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'");
- }
-#endif /* WARNINGS */
-
- return key_len;
-}
-#endif /* WRITE_TEXT || WRITE_pCAL || WRITE_iCCP || WRITE_sPLT */
-
/* Write the IHDR chunk, and update the png_struct with the necessary
* information. Note that the rest of this code depends upon this
* information being correct.
@@ -759,6 +675,7 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, int interlace_type)
{
png_byte buf[13]; /* Buffer to store the IHDR info */
+ int is_invalid_depth;
png_debug(1, "in png_write_IHDR");
@@ -784,11 +701,11 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, break;
case PNG_COLOR_TYPE_RGB:
+ is_invalid_depth = (bit_depth != 8);
#ifdef PNG_WRITE_16BIT_SUPPORTED
- if (bit_depth != 8 && bit_depth != 16)
-#else
- if (bit_depth != 8)
+ is_invalid_depth = (is_invalid_depth && bit_depth != 16);
#endif
+ if (is_invalid_depth)
png_error(png_ptr, "Invalid bit depth for RGB image");
png_ptr->channels = 3;
@@ -810,18 +727,22 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, break;
case PNG_COLOR_TYPE_GRAY_ALPHA:
- if (bit_depth != 8 && bit_depth != 16)
+ is_invalid_depth = (bit_depth != 8);
+#ifdef PNG_WRITE_16BIT_SUPPORTED
+ is_invalid_depth = (is_invalid_depth && bit_depth != 16);
+#endif
+ if (is_invalid_depth)
png_error(png_ptr, "Invalid bit depth for grayscale+alpha image");
png_ptr->channels = 2;
break;
case PNG_COLOR_TYPE_RGB_ALPHA:
+ is_invalid_depth = (bit_depth != 8);
#ifdef PNG_WRITE_16BIT_SUPPORTED
- if (bit_depth != 8 && bit_depth != 16)
-#else
- if (bit_depth != 8)
+ is_invalid_depth = (is_invalid_depth && bit_depth != 16);
#endif
+ if (is_invalid_depth)
png_error(png_ptr, "Invalid bit depth for RGBA image");
png_ptr->channels = 4;
@@ -922,17 +843,20 @@ void /* PRIVATE */ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette,
png_uint_32 num_pal)
{
- png_uint_32 i;
+ png_uint_32 max_palette_length, i;
png_const_colorp pal_ptr;
png_byte buf[3];
png_debug(1, "in png_write_PLTE");
+ max_palette_length = (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
+ (1 << png_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;
+
if ((
#ifdef PNG_MNG_FEATURES_SUPPORTED
(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 &&
#endif
- num_pal == 0) || num_pal > 256)
+ num_pal == 0) || num_pal > max_palette_length)
{
if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
{
@@ -1006,7 +930,7 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, */
void /* PRIVATE */
png_compress_IDAT(png_structrp png_ptr, png_const_bytep input,
- png_alloc_size_t input_len, int flush)
+ png_alloc_size_t input_len, int flush)
{
if (png_ptr->zowner != png_IDAT)
{
@@ -1018,7 +942,7 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, if (png_ptr->zbuffer_list == NULL)
{
png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp,
- png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr)));
+ png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr)));
png_ptr->zbuffer_list->next = NULL;
}
@@ -1257,7 +1181,7 @@ png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette) png_byte new_name[80];
png_byte entrybuf[10];
png_size_t entry_size = (spalette->depth == 8 ? 6 : 10);
- png_size_t palette_size = entry_size * spalette->nentries;
+ png_size_t palette_size = entry_size * (png_size_t)spalette->nentries;
png_sPLT_entryp ep;
#ifndef PNG_POINTER_INDEXING_SUPPORTED
int i;
@@ -1439,12 +1363,12 @@ png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha, /* Write the chunk out as it is */
png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha,
- (png_size_t)num_trans);
+ (png_size_t)num_trans);
}
else if (color_type == PNG_COLOR_TYPE_GRAY)
{
- /* One 16 bit value */
+ /* One 16-bit value */
if (tran->gray >= (1 << png_ptr->bit_depth))
{
png_app_warning(png_ptr,
@@ -1459,7 +1383,7 @@ png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha, else if (color_type == PNG_COLOR_TYPE_RGB)
{
- /* Three 16 bit values */
+ /* Three 16-bit values */
png_save_uint_16(buf, tran->red);
png_save_uint_16(buf + 2, tran->green);
png_save_uint_16(buf + 4, tran->blue);
@@ -1470,7 +1394,7 @@ png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha, #endif
{
png_app_warning(png_ptr,
- "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
+ "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8");
return;
}
@@ -1522,7 +1446,8 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) #endif
{
png_warning(png_ptr,
- "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8");
+ "Ignoring attempt to write 16-bit bKGD chunk "
+ "when bit_depth is 8");
return;
}
@@ -1652,7 +1577,7 @@ png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, /* Compute the compressed data; do it now for the length */
png_text_compress_init(&comp, (png_const_bytep)text,
- text == NULL ? 0 : strlen(text));
+ text == NULL ? 0 : strlen(text));
if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK)
png_error(png_ptr, png_ptr->zstream.msg);
@@ -1823,7 +1748,7 @@ png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, total_len = purpose_len + units_len + 10;
params_len = (png_size_tp)png_malloc(png_ptr,
- (png_alloc_size_t)(nparams * (sizeof (png_size_t))));
+ (png_alloc_size_t)((png_alloc_size_t)nparams * (sizeof (png_size_t))));
/* Find the length of each parameter, making sure we don't count the
* null terminator for the last parameter.
@@ -1961,6 +1886,10 @@ png_write_start_row(png_structrp png_ptr) png_alloc_size_t buf_size;
int usr_pixel_depth;
+#ifdef PNG_WRITE_FILTER_SUPPORTED
+ png_byte filters;
+#endif
+
png_debug(1, "in png_write_start_row");
usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth;
@@ -1971,50 +1900,54 @@ png_write_start_row(png_structrp png_ptr) png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth;
/* Set up row buffer */
- png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, buf_size);
+ png_ptr->row_buf = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size));
png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE;
#ifdef PNG_WRITE_FILTER_SUPPORTED
- /* Set up filtering buffer, if using this filter */
- if (png_ptr->do_filter & PNG_FILTER_SUB)
- {
- png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1);
+ filters = png_ptr->do_filter;
- png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB;
- }
+ if (png_ptr->height == 1)
+ filters &= 0xff & ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH);
+
+ if (png_ptr->width == 1)
+ filters &= 0xff & ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH);
+
+ if (filters == 0)
+ filters = PNG_FILTER_NONE;
- /* We only need to keep the previous row if we are using one of these. */
- if ((png_ptr->do_filter &
- (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) != 0)
+ png_ptr->do_filter = filters;
+
+ if (((filters & (PNG_FILTER_SUB | PNG_FILTER_UP | PNG_FILTER_AVG |
+ PNG_FILTER_PAETH)) != 0) && png_ptr->try_row == NULL)
{
- /* Set up previous row buffer */
- png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, buf_size);
+ int num_filters = 0;
- if ((png_ptr->do_filter & PNG_FILTER_UP) != 0)
- {
- png_ptr->up_row = (png_bytep)png_malloc(png_ptr,
- png_ptr->rowbytes + 1);
+ png_ptr->try_row = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size));
- png_ptr->up_row[0] = PNG_FILTER_VALUE_UP;
- }
+ if (filters & PNG_FILTER_SUB)
+ num_filters++;
- if ((png_ptr->do_filter & PNG_FILTER_AVG) != 0)
- {
- png_ptr->avg_row = (png_bytep)png_malloc(png_ptr,
- png_ptr->rowbytes + 1);
+ if (filters & PNG_FILTER_UP)
+ num_filters++;
- png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG;
- }
+ if (filters & PNG_FILTER_AVG)
+ num_filters++;
- if ((png_ptr->do_filter & PNG_FILTER_PAETH) != 0)
- {
- png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr,
- png_ptr->rowbytes + 1);
+ if (filters & PNG_FILTER_PAETH)
+ num_filters++;
- png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH;
- }
+ if (num_filters > 1)
+ png_ptr->tst_row = png_voidcast(png_bytep, png_malloc(png_ptr,
+ buf_size));
}
+
+ /* We only need to keep the previous row if we are using one of the following
+ * filters.
+ */
+ if ((filters & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) != 0)
+ png_ptr->prev_row = png_voidcast(png_bytep,
+ png_calloc(png_ptr, buf_size));
#endif /* WRITE_FILTER */
#ifdef PNG_WRITE_INTERLACING_SUPPORTED
@@ -2160,7 +2093,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) {
png_bytep sp;
png_bytep dp;
- int shift;
+ unsigned int shift;
int d;
int value;
png_uint_32 i;
@@ -2198,7 +2131,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) {
png_bytep sp;
png_bytep dp;
- int shift;
+ unsigned int shift;
int d;
int value;
png_uint_32 i;
@@ -2235,7 +2168,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) {
png_bytep sp;
png_bytep dp;
- int shift;
+ unsigned int shift;
int d;
int value;
png_uint_32 i;
@@ -2310,684 +2243,480 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) }
#endif
+
/* This filters the row, chooses which filter to use, if it has not already
* been specified by the application, and then writes the row out with the
* chosen filter.
*/
static void /* PRIVATE */
png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
- png_size_t row_bytes);
+ png_size_t row_bytes);
-#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1)
-#define PNG_HISHIFT 10
-#define PNG_LOMASK ((png_uint_32)0xffffL)
-#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
-void /* PRIVATE */
-png_write_find_filter(png_structrp png_ptr, png_row_infop row_info)
-{
- png_bytep best_row;
#ifdef PNG_WRITE_FILTER_SUPPORTED
- png_bytep prev_row, row_buf;
- png_uint_32 mins, bpp;
- png_byte filter_to_do = png_ptr->do_filter;
- png_size_t row_bytes = row_info->rowbytes;
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- int num_p_filters = png_ptr->num_prev_filters;
-#endif
-
- png_debug(1, "in png_write_find_filter");
-
-#ifndef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->row_number == 0 && filter_to_do == PNG_ALL_FILTERS)
- {
- /* These will never be selected so we need not test them. */
- filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH);
- }
-#endif
-
- /* Find out how many bytes offset each pixel is */
- bpp = (row_info->pixel_depth + 7) >> 3;
-
- prev_row = png_ptr->prev_row;
-#endif
- best_row = png_ptr->row_buf;
-#ifdef PNG_WRITE_FILTER_SUPPORTED
- row_buf = best_row;
- mins = PNG_MAXSUM;
-
- /* The prediction method we use is to find which method provides the
- * smallest value when summing the absolute values of the distances
- * from zero, using anything >= 128 as negative numbers. This is known
- * as the "minimum sum of absolute differences" heuristic. Other
- * heuristics are the "weighted minimum sum of absolute differences"
- * (experimental and can in theory improve compression), and the "zlib
- * predictive" method (not implemented yet), which does test compressions
- * of lines using different filter methods, and then chooses the
- * (series of) filter(s) that give minimum compressed data size (VERY
- * computationally expensive).
- *
- * GRR 980525: consider also
- *
- * (1) minimum sum of absolute differences from running average (i.e.,
- * keep running sum of non-absolute differences & count of bytes)
- * [track dispersion, too? restart average if dispersion too large?]
- *
- * (1b) minimum sum of absolute differences from sliding average, probably
- * with window size <= deflate window (usually 32K)
- *
- * (2) minimum sum of squared differences from zero or running average
- * (i.e., ~ root-mean-square approach)
- */
+static png_size_t /* PRIVATE */
+png_setup_sub_row(png_structrp png_ptr, const png_uint_32 bpp,
+ const png_size_t row_bytes, const png_size_t lmins)
+{
+ png_bytep rp, dp, lp;
+ png_size_t i;
+ png_size_t sum = 0;
+ unsigned int v;
+ png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB;
- /* We don't need to test the 'no filter' case if this is the only filter
- * that has been chosen, as it doesn't actually do anything to the data.
- */
- if ((filter_to_do & PNG_FILTER_NONE) != 0 && filter_to_do != PNG_FILTER_NONE)
+ for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp;
+ i++, rp++, dp++)
{
- png_bytep rp;
- png_uint_32 sum = 0;
- png_size_t i;
- int v;
-
- for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
- {
- v = *rp;
- sum += (v < 128) ? v : 256 - v;
- }
-
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- png_uint_32 sumhi, sumlo;
- int j;
- sumlo = sum & PNG_LOMASK;
- sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */
-
- /* Reduce the sum if we match any of the previous rows */
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
- {
- sumlo = (sumlo * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
-
- sumhi = (sumhi * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
-
- /* Factor in the cost of this filter (this is here for completeness,
- * but it makes no sense to have a "cost" for the NONE filter, as
- * it has the minimum possible computational cost - none).
- */
- sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
- PNG_COST_SHIFT;
-
- sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >>
- PNG_COST_SHIFT;
-
- if (sumhi > PNG_HIMASK)
- sum = PNG_MAXSUM;
-
- else
- sum = (sumhi << PNG_HISHIFT) + sumlo;
- }
+ v = *dp = *rp;
+#ifdef PNG_USE_ABS
+ sum += 128 - abs((int)v - 128);
+#else
+ sum += (v < 128) ? v : 256 - v;
#endif
- mins = sum;
}
- /* Sub filter */
- if (filter_to_do == PNG_FILTER_SUB)
- /* It's the only filter so no testing is needed */
+ for (lp = png_ptr->row_buf + 1; i < row_bytes;
+ i++, rp++, lp++, dp++)
{
- png_bytep rp, lp, dp;
- png_size_t i;
-
- for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
- i++, rp++, dp++)
- {
- *dp = *rp;
- }
-
- for (lp = row_buf + 1; i < row_bytes;
- i++, rp++, lp++, dp++)
- {
- *dp = (png_byte)((int)*rp - (int)*lp);
- }
+ v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
+#ifdef PNG_USE_ABS
+ sum += 128 - abs((int)v - 128);
+#else
+ sum += (v < 128) ? v : 256 - v;
+#endif
- best_row = png_ptr->sub_row;
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
}
- else if ((filter_to_do & PNG_FILTER_SUB) != 0)
- {
- png_bytep rp, dp, lp;
- png_uint_32 sum = 0, lmins = mins;
- png_size_t i;
- int v;
+ return (sum);
+}
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- /* We temporarily increase the "minimum sum" by the factor we
- * would reduce the sum of this filter, so that we can do the
- * early exit comparison without scaling the sum each time.
- */
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 lmhi, lmlo;
- lmlo = lmins & PNG_LOMASK;
- lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+static void /* PRIVATE */
+png_setup_sub_row_only(png_structrp png_ptr, const png_uint_32 bpp,
+ const png_size_t row_bytes)
+{
+ png_bytep rp, dp, lp;
+ png_size_t i;
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
- {
- lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
+ png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB;
- lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
+ for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp;
+ i++, rp++, dp++)
+ {
+ *dp = *rp;
+ }
- lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
- PNG_COST_SHIFT;
+ for (lp = png_ptr->row_buf + 1; i < row_bytes;
+ i++, rp++, lp++, dp++)
+ {
+ *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
+ }
+}
- lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
- PNG_COST_SHIFT;
+static png_size_t /* PRIVATE */
+png_setup_up_row(png_structrp png_ptr, const png_size_t row_bytes,
+ const png_size_t lmins)
+{
+ png_bytep rp, dp, pp;
+ png_size_t i;
+ png_size_t sum = 0;
+ unsigned int v;
- if (lmhi > PNG_HIMASK)
- lmins = PNG_MAXSUM;
+ png_ptr->try_row[0] = PNG_FILTER_VALUE_UP;
- else
- lmins = (lmhi << PNG_HISHIFT) + lmlo;
- }
+ for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
+ pp = png_ptr->prev_row + 1; i < row_bytes;
+ i++, rp++, pp++, dp++)
+ {
+ v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
+#ifdef PNG_USE_ABS
+ sum += 128 - abs((int)v - 128);
+#else
+ sum += (v < 128) ? v : 256 - v;
#endif
- for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp;
- i++, rp++, dp++)
- {
- v = *dp = *rp;
-
- sum += (v < 128) ? v : 256 - v;
- }
-
- for (lp = row_buf + 1; i < row_bytes;
- i++, rp++, lp++, dp++)
- {
- v = *dp = (png_byte)((int)*rp - (int)*lp);
-
- sum += (v < 128) ? v : 256 - v;
-
- if (sum > lmins) /* We are already worse, don't continue. */
- break;
- }
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
+ }
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 sumhi, sumlo;
- sumlo = sum & PNG_LOMASK;
- sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+ return (sum);
+}
+static void /* PRIVATE */
+png_setup_up_row_only(png_structrp png_ptr, const png_size_t row_bytes)
+{
+ png_bytep rp, dp, pp;
+ png_size_t i;
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB)
- {
- sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
+ png_ptr->try_row[0] = PNG_FILTER_VALUE_UP;
- sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
+ for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
+ pp = png_ptr->prev_row + 1; i < row_bytes;
+ i++, rp++, pp++, dp++)
+ {
+ *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
+ }
+}
- sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
- PNG_COST_SHIFT;
+static png_size_t /* PRIVATE */
+png_setup_avg_row(png_structrp png_ptr, const png_uint_32 bpp,
+ const png_size_t row_bytes, const png_size_t lmins)
+{
+ png_bytep rp, dp, pp, lp;
+ png_uint_32 i;
+ png_size_t sum = 0;
+ unsigned int v;
- sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
- PNG_COST_SHIFT;
+ png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG;
- if (sumhi > PNG_HIMASK)
- sum = PNG_MAXSUM;
+ for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
+ pp = png_ptr->prev_row + 1; i < bpp; i++)
+ {
+ v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
- else
- sum = (sumhi << PNG_HISHIFT) + sumlo;
- }
+#ifdef PNG_USE_ABS
+ sum += 128 - abs((int)v - 128);
+#else
+ sum += (v < 128) ? v : 256 - v;
#endif
-
- if (sum < mins)
- {
- mins = sum;
- best_row = png_ptr->sub_row;
- }
}
- /* Up filter */
- if (filter_to_do == PNG_FILTER_UP)
+ for (lp = png_ptr->row_buf + 1; i < row_bytes; i++)
{
- png_bytep rp, dp, pp;
- png_size_t i;
+ v = *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
+ & 0xff);
- for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
- pp = prev_row + 1; i < row_bytes;
- i++, rp++, pp++, dp++)
- {
- *dp = (png_byte)((int)*rp - (int)*pp);
- }
+#ifdef PNG_USE_ABS
+ sum += 128 - abs((int)v - 128);
+#else
+ sum += (v < 128) ? v : 256 - v;
+#endif
- best_row = png_ptr->up_row;
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
}
- else if ((filter_to_do & PNG_FILTER_UP) != 0)
- {
- png_bytep rp, dp, pp;
- png_uint_32 sum = 0, lmins = mins;
- png_size_t i;
- int v;
-
+ return (sum);
+}
+static void /* PRIVATE */
+png_setup_avg_row_only(png_structrp png_ptr, const png_uint_32 bpp,
+ const png_size_t row_bytes)
+{
+ png_bytep rp, dp, pp, lp;
+ png_uint_32 i;
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 lmhi, lmlo;
- lmlo = lmins & PNG_LOMASK;
- lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+ png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG;
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
- {
- lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
+ for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
+ pp = png_ptr->prev_row + 1; i < bpp; i++)
+ {
+ *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff);
+ }
- lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
+ for (lp = png_ptr->row_buf + 1; i < row_bytes; i++)
+ {
+ *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2))
+ & 0xff);
+ }
+}
- lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
- PNG_COST_SHIFT;
+static png_size_t /* PRIVATE */
+png_setup_paeth_row(png_structrp png_ptr, const png_uint_32 bpp,
+ const png_size_t row_bytes, const png_size_t lmins)
+{
+ png_bytep rp, dp, pp, cp, lp;
+ png_size_t i;
+ png_size_t sum = 0;
+ unsigned int v;
- lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
- PNG_COST_SHIFT;
+ png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH;
- if (lmhi > PNG_HIMASK)
- lmins = PNG_MAXSUM;
+ for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
+ pp = png_ptr->prev_row + 1; i < bpp; i++)
+ {
+ v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
- else
- lmins = (lmhi << PNG_HISHIFT) + lmlo;
- }
+#ifdef PNG_USE_ABS
+ sum += 128 - abs((int)v - 128);
+#else
+ sum += (v < 128) ? v : 256 - v;
#endif
+ }
- for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
- pp = prev_row + 1; i < row_bytes; i++)
- {
- v = *dp++ = (png_byte)((int)*rp++ - (int)*pp++);
-
- sum += (v < 128) ? v : 256 - v;
-
- if (sum > lmins) /* We are already worse, don't continue. */
- break;
- }
-
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 sumhi, sumlo;
- sumlo = sum & PNG_LOMASK;
- sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+ for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes;
+ i++)
+ {
+ int a, b, c, pa, pb, pc, p;
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP)
- {
- sumlo = (sumlo * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
+ b = *pp++;
+ c = *cp++;
+ a = *lp++;
- sumhi = (sumhi * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
+ p = b - c;
+ pc = a - c;
- sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
- PNG_COST_SHIFT;
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+#endif
- sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >>
- PNG_COST_SHIFT;
+ p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
- if (sumhi > PNG_HIMASK)
- sum = PNG_MAXSUM;
+ v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
- else
- sum = (sumhi << PNG_HISHIFT) + sumlo;
- }
+#ifdef PNG_USE_ABS
+ sum += 128 - abs((int)v - 128);
+#else
+ sum += (v < 128) ? v : 256 - v;
#endif
- if (sum < mins)
- {
- mins = sum;
- best_row = png_ptr->up_row;
- }
+ if (sum > lmins) /* We are already worse, don't continue. */
+ break;
}
- /* Avg filter */
- if (filter_to_do == PNG_FILTER_AVG)
- {
- png_bytep rp, dp, pp, lp;
- png_uint_32 i;
+ return (sum);
+}
+static void /* PRIVATE */
+png_setup_paeth_row_only(png_structrp png_ptr, const png_uint_32 bpp,
+ const png_size_t row_bytes)
+{
+ png_bytep rp, dp, pp, cp, lp;
+ png_size_t i;
- for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
- pp = prev_row + 1; i < bpp; i++)
- {
- *dp++ = (png_byte)((int)*rp++ - ((int)*pp++ / 2));
- }
+ png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH;
- for (lp = row_buf + 1; i < row_bytes; i++)
- {
- *dp++ =
- (png_byte)((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2));
- }
- best_row = png_ptr->avg_row;
+ for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1,
+ pp = png_ptr->prev_row + 1; i < bpp; i++)
+ {
+ *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff);
}
- else if ((filter_to_do & PNG_FILTER_AVG) != 0)
+ for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes;
+ i++)
{
- png_bytep rp, dp, pp, lp;
- png_uint_32 sum = 0, lmins = mins;
- png_size_t i;
- int v;
-
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 lmhi, lmlo;
- lmlo = lmins & PNG_LOMASK;
- lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG)
- {
- lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
-
- lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
+ int a, b, c, pa, pb, pc, p;
- lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
- PNG_COST_SHIFT;
+ b = *pp++;
+ c = *cp++;
+ a = *lp++;
- lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >>
- PNG_COST_SHIFT;
+ p = b - c;
+ pc = a - c;
- if (lmhi > PNG_HIMASK)
- lmins = PNG_MAXSUM;
-
- else
- lmins = (lmhi << PNG_HISHIFT) + lmlo;
- }
+#ifdef PNG_USE_ABS
+ pa = abs(p);
+ pb = abs(pc);
+ pc = abs(p + pc);
+#else
+ pa = p < 0 ? -p : p;
+ pb = pc < 0 ? -pc : pc;
+ pc = (p + pc) < 0 ? -(p + pc) : p + pc;
#endif
- for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
- pp = prev_row + 1; i < bpp; i++)
- {
- v = *dp++ = (png_byte)((int)*rp++ - ((int)*pp++ / 2));
-
- sum += (v < 128) ? v : 256 - v;
- }
-
- for (lp = row_buf + 1; i < row_bytes; i++)
- {
- v = *dp++ =
- (png_byte)(((int)*rp++ - ((int)*pp++ + (int)*lp++) / 2));
-
- sum += (v < 128) ? v : 256 - v;
+ p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
- if (sum > lmins) /* We are already worse, don't continue. */
- break;
- }
+ *dp++ = (png_byte)(((int)*rp++ - p) & 0xff);
+ }
+}
+#endif /* WRITE_FILTER */
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 sumhi, sumlo;
- sumlo = sum & PNG_LOMASK;
- sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
+void /* PRIVATE */
+png_write_find_filter(png_structrp png_ptr, png_row_infop row_info)
+{
+#ifndef PNG_WRITE_FILTER_SUPPORTED
+ png_write_filtered_row(png_ptr, png_ptr->row_buf, row_info->rowbytes+1);
+#else
+ unsigned int filter_to_do = png_ptr->do_filter;
+ png_bytep row_buf;
+ png_bytep best_row;
+ png_uint_32 bpp;
+ png_size_t mins;
+ png_size_t row_bytes = row_info->rowbytes;
- for (j = 0; j < num_p_filters; j++)
- {
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE)
- {
- sumlo = (sumlo * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
+ png_debug(1, "in png_write_find_filter");
- sumhi = (sumhi * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
- }
+ /* Find out how many bytes offset each pixel is */
+ bpp = (row_info->pixel_depth + 7) >> 3;
- sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
- PNG_COST_SHIFT;
+ row_buf = png_ptr->row_buf;
+ mins = PNG_SIZE_MAX - 256/* so we can detect potential overflow of the
+ running sum */;
- sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >>
- PNG_COST_SHIFT;
+ /* The prediction method we use is to find which method provides the
+ * smallest value when summing the absolute values of the distances
+ * from zero, using anything >= 128 as negative numbers. This is known
+ * as the "minimum sum of absolute differences" heuristic. Other
+ * heuristics are the "weighted minimum sum of absolute differences"
+ * (experimental and can in theory improve compression), and the "zlib
+ * predictive" method (not implemented yet), which does test compressions
+ * of lines using different filter methods, and then chooses the
+ * (series of) filter(s) that give minimum compressed data size (VERY
+ * computationally expensive).
+ *
+ * GRR 980525: consider also
+ *
+ * (1) minimum sum of absolute differences from running average (i.e.,
+ * keep running sum of non-absolute differences & count of bytes)
+ * [track dispersion, too? restart average if dispersion too large?]
+ *
+ * (1b) minimum sum of absolute differences from sliding average, probably
+ * with window size <= deflate window (usually 32K)
+ *
+ * (2) minimum sum of squared differences from zero or running average
+ * (i.e., ~ root-mean-square approach)
+ */
- if (sumhi > PNG_HIMASK)
- sum = PNG_MAXSUM;
- else
- sum = (sumhi << PNG_HISHIFT) + sumlo;
- }
-#endif
+ /* We don't need to test the 'no filter' case if this is the only filter
+ * that has been chosen, as it doesn't actually do anything to the data.
+ */
+ best_row = png_ptr->row_buf;
- if (sum < mins)
- {
- mins = sum;
- best_row = png_ptr->avg_row;
- }
+ if (PNG_SIZE_MAX/128 <= row_bytes)
+ {
+ /* Overflow can occur in the calculation, just select the lowest set
+ * filter.
+ */
+ filter_to_do &= 0U-filter_to_do;
}
-
- /* Paeth filter */
- if ((filter_to_do == PNG_FILTER_PAETH) != 0)
+ else if ((filter_to_do & PNG_FILTER_NONE) != 0 &&
+ filter_to_do != PNG_FILTER_NONE)
{
- png_bytep rp, dp, pp, cp, lp;
+ /* Overflow not possible and multiple filters in the list, including the
+ * 'none' filter.
+ */
+ png_bytep rp;
+ png_size_t sum = 0;
png_size_t i;
+ unsigned int v;
- for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
- pp = prev_row + 1; i < bpp; i++)
{
- *dp++ = (png_byte)((int)*rp++ - (int)*pp++);
- }
-
- for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
- {
- int a, b, c, pa, pb, pc, p;
-
- b = *pp++;
- c = *cp++;
- a = *lp++;
-
- p = b - c;
- pc = a - c;
-
+ for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
+ {
+ v = *rp;
#ifdef PNG_USE_ABS
- pa = abs(p);
- pb = abs(pc);
- pc = abs(p + pc);
+ sum += 128 - abs((int)v - 128);
#else
- pa = p < 0 ? -p : p;
- pb = pc < 0 ? -pc : pc;
- pc = (p + pc) < 0 ? -(p + pc) : p + pc;
+ sum += (v < 128) ? v : 256 - v;
#endif
+ }
+ }
- p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
+ mins = sum;
+ }
- *dp++ = (png_byte)((int)*rp++ - p);
- }
- best_row = png_ptr->paeth_row;
+ /* Sub filter */
+ if (filter_to_do == PNG_FILTER_SUB)
+ /* It's the only filter so no testing is needed */
+ {
+ png_setup_sub_row_only(png_ptr, bpp, row_bytes);
+ best_row = png_ptr->try_row;
}
- else if ((filter_to_do & PNG_FILTER_PAETH) != 0)
+ else if ((filter_to_do & PNG_FILTER_SUB) != 0)
{
- png_bytep rp, dp, pp, cp, lp;
- png_uint_32 sum = 0, lmins = mins;
- png_size_t i;
- int v;
+ png_size_t sum;
+ png_size_t lmins = mins;
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
- {
- int j;
- png_uint_32 lmhi, lmlo;
- lmlo = lmins & PNG_LOMASK;
- lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK;
+ sum = png_setup_sub_row(png_ptr, bpp, row_bytes, lmins);
- for (j = 0; j < num_p_filters; j++)
+ if (sum < mins)
+ {
+ mins = sum;
+ best_row = png_ptr->try_row;
+ if (png_ptr->tst_row != NULL)
{
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
- {
- lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
-
- lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
+ png_ptr->try_row = png_ptr->tst_row;
+ png_ptr->tst_row = best_row;
}
+ }
+ }
- lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
- PNG_COST_SHIFT;
-
- lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >>
- PNG_COST_SHIFT;
+ /* Up filter */
+ if (filter_to_do == PNG_FILTER_UP)
+ {
+ png_setup_up_row_only(png_ptr, row_bytes);
+ best_row = png_ptr->try_row;
+ }
- if (lmhi > PNG_HIMASK)
- lmins = PNG_MAXSUM;
+ else if ((filter_to_do & PNG_FILTER_UP) != 0)
+ {
+ png_size_t sum;
+ png_size_t lmins = mins;
- else
- lmins = (lmhi << PNG_HISHIFT) + lmlo;
- }
-#endif
+ sum = png_setup_up_row(png_ptr, row_bytes, lmins);
- for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
- pp = prev_row + 1; i < bpp; i++)
+ if (sum < mins)
{
- v = *dp++ = (png_byte)((int)*rp++ - (int)*pp++);
-
- sum += (v < 128) ? v : 256 - v;
+ mins = sum;
+ best_row = png_ptr->try_row;
+ if (png_ptr->tst_row != NULL)
+ {
+ png_ptr->try_row = png_ptr->tst_row;
+ png_ptr->tst_row = best_row;
+ }
}
+ }
- for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++)
- {
- int a, b, c, pa, pb, pc, p;
-
- b = *pp++;
- c = *cp++;
- a = *lp++;
-
-#ifndef PNG_SLOW_PAETH
- p = b - c;
- pc = a - c;
-#ifdef PNG_USE_ABS
- pa = abs(p);
- pb = abs(pc);
- pc = abs(p + pc);
-#else
- pa = p < 0 ? -p : p;
- pb = pc < 0 ? -pc : pc;
- pc = (p + pc) < 0 ? -(p + pc) : p + pc;
-#endif
- p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c;
-#else /* SLOW_PAETH */
- p = a + b - c;
- pa = abs(p - a);
- pb = abs(p - b);
- pc = abs(p - c);
-
- if (pa <= pb && pa <= pc)
- p = a;
-
- else if (pb <= pc)
- p = b;
-
- else
- p = c;
-#endif /* SLOW_PAETH */
-
- v = *dp++ = (png_byte)((int)*rp++ - p);
+ /* Avg filter */
+ if (filter_to_do == PNG_FILTER_AVG)
+ {
+ png_setup_avg_row_only(png_ptr, bpp, row_bytes);
+ best_row = png_ptr->try_row;
+ }
- sum += (v < 128) ? v : 256 - v;
+ else if ((filter_to_do & PNG_FILTER_AVG) != 0)
+ {
+ png_size_t sum;
+ png_size_t lmins = mins;
- if (sum > lmins) /* We are already worse, don't continue. */
- break;
- }
+ sum= png_setup_avg_row(png_ptr, bpp, row_bytes, lmins);
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED)
+ if (sum < mins)
{
- int j;
- png_uint_32 sumhi, sumlo;
- sumlo = sum & PNG_LOMASK;
- sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK;
-
- for (j = 0; j < num_p_filters; j++)
+ mins = sum;
+ best_row = png_ptr->try_row;
+ if (png_ptr->tst_row != NULL)
{
- if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH)
- {
- sumlo = (sumlo * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
-
- sumhi = (sumhi * png_ptr->filter_weights[j]) >>
- PNG_WEIGHT_SHIFT;
- }
+ png_ptr->try_row = png_ptr->tst_row;
+ png_ptr->tst_row = best_row;
}
+ }
+ }
- sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
- PNG_COST_SHIFT;
-
- sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >>
- PNG_COST_SHIFT;
+ /* Paeth filter */
+ if (filter_to_do == PNG_FILTER_PAETH)
+ {
+ png_setup_paeth_row_only(png_ptr, bpp, row_bytes);
+ best_row = png_ptr->try_row;
+ }
- if (sumhi > PNG_HIMASK)
- sum = PNG_MAXSUM;
+ else if ((filter_to_do & PNG_FILTER_PAETH) != 0)
+ {
+ png_size_t sum;
+ png_size_t lmins = mins;
- else
- sum = (sumhi << PNG_HISHIFT) + sumlo;
- }
-#endif
+ sum = png_setup_paeth_row(png_ptr, bpp, row_bytes, lmins);
if (sum < mins)
{
- best_row = png_ptr->paeth_row;
+ best_row = png_ptr->try_row;
+ if (png_ptr->tst_row != NULL)
+ {
+ png_ptr->try_row = png_ptr->tst_row;
+ png_ptr->tst_row = best_row;
+ }
}
}
-#endif /* WRITE_FILTER */
/* Do the actual writing of the filtered row data from the chosen filter. */
png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1);
-#ifdef PNG_WRITE_FILTER_SUPPORTED
-#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED
- /* Save the type of filter we picked this time for future calculations */
- if (png_ptr->num_prev_filters > 0)
- {
- int j;
-
- for (j = 1; j < num_p_filters; j++)
- {
- png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1];
- }
-
- png_ptr->prev_filters[j] = best_row[0];
- }
-#endif
#endif /* WRITE_FILTER */
}
@@ -2995,7 +2724,7 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) /* Do the actual writing of a previously filtered row. */
static void
png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row,
- png_size_t full_row_length/*includes filter byte*/)
+ png_size_t full_row_length/*includes filter byte*/)
{
png_debug(1, "in png_write_filtered_row");
|