diff --git a/ANNOUNCE b/ANNOUNCE index da4eebe51..f506c831b 100644 --- a/ANNOUNCE +++ b/ANNOUNCE @@ -45,6 +45,9 @@ Version 1.6.24beta02 [June 19, 2016] implemented in 1.7), however a simple safe fix here is to chose the lowest numbered filter in the list from png_set_filter (this only works if the first problem is also fixed) (John Bowler). + Avoid filter-selection heuristic sum calculations in cases where only one + filter is a candidate for selection. This trades off code size (added + png_setup_*_row_only() functions) for speed. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/CHANGES b/CHANGES index 2fc0222c3..ee7c0d518 100644 --- a/CHANGES +++ b/CHANGES @@ -5616,6 +5616,9 @@ Version 1.6.24beta02 [June 19, 2016] implemented in 1.7), however a simple safe fix here is to chose the lowest numbered filter in the list from png_set_filter (this only works if the first problem is also fixed) (John Bowler). + Avoid filter-selection heuristic sum calculations in cases where only one + filter is a candidate for selection. This trades off code size (added + png_setup_*_row_only() functions) for speed. Send comments/corrections/commendations to png-mng-implement at lists.sf.net (subscription required; visit diff --git a/pngwutil.c b/pngwutil.c index 2e4d1a567..30b0a9702 100644 --- a/pngwutil.c +++ b/pngwutil.c @@ -2278,6 +2278,28 @@ png_setup_sub_row(png_structrp png_ptr, const png_uint_32 bpp, return (sum); } +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; + + png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB; + + for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp; + i++, rp++, dp++) + { + *dp = *rp; + } + + for (lp = png_ptr->row_buf + 1; i < row_bytes; + i++, rp++, lp++, dp++) + { + *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + } +} + static png_size_t /* PRIVATE */ png_setup_up_row(png_structrp png_ptr, const png_size_t row_bytes, const png_size_t lmins) @@ -2302,6 +2324,21 @@ png_setup_up_row(png_structrp png_ptr, const png_size_t row_bytes, 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; + + png_ptr->try_row[0] = PNG_FILTER_VALUE_UP; + + 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); + } +} static png_size_t /* PRIVATE */ png_setup_avg_row(png_structrp png_ptr, const png_uint_32 bpp, @@ -2335,6 +2372,27 @@ png_setup_avg_row(png_structrp png_ptr, const png_uint_32 bpp, 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; + + png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG; + + 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); + } + + for (lp = png_ptr->row_buf + 1; i < row_bytes; i++) + { + *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) + & 0xff); + } +} static png_size_t /* PRIVATE */ png_setup_paeth_row(png_structrp png_ptr, const png_uint_32 bpp, @@ -2389,6 +2447,48 @@ png_setup_paeth_row(png_structrp png_ptr, const png_uint_32 bpp, 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; + + png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH; + + 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); + } + + 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; + + b = *pp++; + c = *cp++; + a = *lp++; + + 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; + + *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + } +} #endif /* WRITE_FILTER */ void /* PRIVATE */ @@ -2476,10 +2576,7 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) if (filter_to_do == PNG_FILTER_SUB) /* It's the only filter so no testing is needed */ { - /* Passing PNG_SIZE_MAX here and below prevents the 'setup' function - * breaking out of the loop when lmins is exceeded. - */ - (void) png_setup_sub_row(png_ptr, bpp, row_bytes, PNG_SIZE_MAX); + png_setup_sub_row_only(png_ptr, bpp, row_bytes); best_row = png_ptr->try_row; } @@ -2505,7 +2602,7 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) /* Up filter */ if (filter_to_do == PNG_FILTER_UP) { - (void) png_setup_up_row(png_ptr, row_bytes, PNG_SIZE_MAX); + png_setup_up_row_only(png_ptr, row_bytes); best_row = png_ptr->try_row; } @@ -2531,7 +2628,7 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) /* Avg filter */ if (filter_to_do == PNG_FILTER_AVG) { - (void) png_setup_avg_row(png_ptr, bpp, row_bytes, PNG_SIZE_MAX); + png_setup_avg_row_only(png_ptr, bpp, row_bytes); best_row = png_ptr->try_row; } @@ -2557,7 +2654,7 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) /* Paeth filter */ if ((filter_to_do == PNG_FILTER_PAETH) != 0) { - (void) png_setup_paeth_row(png_ptr, bpp, row_bytes, PNG_SIZE_MAX); + png_setup_paeth_row_only(png_ptr, bpp, row_bytes); best_row = png_ptr->try_row; }