📄 pngwutil.c
字号:
#else
if (pass < 6)
#endif
{
/* each pixel depth is handled separately */
switch (row_info->pixel_depth)
{
case 1:
{
png_bytep sp;
png_bytep dp;
int shift;
int d;
int value;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
dp = row;
d = 0;
shift = 7;
for (i = png_pass_start[pass]; i < row_width;
i += png_pass_inc[pass])
{
sp = row + (png_size_t)(i >> 3);
value = (int)(*sp >> (7 - (int)(i & 7))) & 0x1;
d |= (value << shift);
if (shift == 0)
{
shift = 7;
*dp++ = (png_byte)d;
d = 0;
}
else
shift--;
}
if (shift != 7)
*dp = (png_byte)d;
break;
}
case 2:
{
png_bytep sp;
png_bytep dp;
int shift;
int d;
int value;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
dp = row;
shift = 6;
d = 0;
for (i = png_pass_start[pass]; i < row_width;
i += png_pass_inc[pass])
{
sp = row + (png_size_t)(i >> 2);
value = (*sp >> ((3 - (int)(i & 3)) << 1)) & 0x3;
d |= (value << shift);
if (shift == 0)
{
shift = 6;
*dp++ = (png_byte)d;
d = 0;
}
else
shift -= 2;
}
if (shift != 6)
*dp = (png_byte)d;
break;
}
case 4:
{
png_bytep sp;
png_bytep dp;
int shift;
int d;
int value;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
dp = row;
shift = 4;
d = 0;
for (i = png_pass_start[pass]; i < row_width;
i += png_pass_inc[pass])
{
sp = row + (png_size_t)(i >> 1);
value = (*sp >> ((1 - (int)(i & 1)) << 2)) & 0xf;
d |= (value << shift);
if (shift == 0)
{
shift = 4;
*dp++ = (png_byte)d;
d = 0;
}
else
shift -= 4;
}
if (shift != 4)
*dp = (png_byte)d;
break;
}
default:
{
png_bytep sp;
png_bytep dp;
png_uint_32 i;
png_uint_32 row_width = row_info->width;
png_size_t pixel_bytes;
/* start at the beginning */
dp = row;
/* find out how many bytes each pixel takes up */
pixel_bytes = (row_info->pixel_depth >> 3);
/* loop through the row, only looking at the pixels that
matter */
for (i = png_pass_start[pass]; i < row_width;
i += png_pass_inc[pass])
{
/* find out where the original pixel is */
sp = row + (png_size_t)i * pixel_bytes;
/* move the pixel */
if (dp != sp)
png_memcpy(dp, sp, pixel_bytes);
/* next pixel */
dp += pixel_bytes;
}
break;
}
}
/* set new row width */
row_info->width = (row_info->width +
png_pass_inc[pass] - 1 -
png_pass_start[pass]) /
png_pass_inc[pass];
row_info->rowbytes = ((row_info->width *
row_info->pixel_depth + 7) >> 3);
}
}
#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.
*/
#define PNG_MAXSUM (~((png_uint_32)0) >> 1)
#define PNG_HISHIFT 10
#define PNG_LOMASK ((png_uint_32)0xffffL)
#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT))
void
png_write_find_filter(png_structp png_ptr, png_row_infop row_info)
{
png_bytep prev_row, best_row, row_buf;
png_uint_32 mins, bpp;
png_byte filter_to_do = png_ptr->do_filter;
png_uint_32 row_bytes = row_info->rowbytes;
#if defined(PNG_WRITE_WEIGHTED_FILTER_SUPPORTED)
int num_p_filters = (int)png_ptr->num_prev_filters;
#endif
png_debug(1, "in png_write_find_filter\n");
/* find out how many bytes offset each pixel is */
bpp = (row_info->pixel_depth + 7) / 8;
prev_row = png_ptr->prev_row;
best_row = row_buf = png_ptr->row_buf;
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)
*/
/* 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 &&
filter_to_do != PNG_FILTER_NONE)
{
png_bytep rp;
png_uint_32 sum = 0;
png_uint_32 i;
int v;
for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++)
{
v = *rp;
sum += (v < 128) ? v : 256 - v;
}
#if defined(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;
}
#endif
mins = sum;
}
/* sub filter */
if (filter_to_do == PNG_FILTER_SUB)
/* it's the only filter so no testing is needed */
{
png_bytep rp, lp, dp;
png_uint_32 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) & 0xff);
}
best_row = png_ptr->sub_row;
}
else if (filter_to_do & PNG_FILTER_SUB)
{
png_bytep rp, dp, lp;
png_uint_32 sum = 0, lmins = mins;
png_uint_32 i;
int v;
#if defined(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;
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;
lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
}
}
lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
PNG_COST_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
PNG_COST_SHIFT;
if (lmhi > PNG_HIMASK)
lmins = PNG_MAXSUM;
else
lmins = (lmhi << PNG_HISHIFT) + lmlo;
}
#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_info->rowbytes;
i++, rp++, lp++, dp++)
{
v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff);
sum += (v < 128) ? v : 256 - v;
if (sum > lmins) /* We are already worse, don't continue. */
break;
}
#if defined(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 (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;
sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
}
}
sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
PNG_COST_SHIFT;
sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >>
PNG_COST_SHIFT;
if (sumhi > PNG_HIMASK)
sum = PNG_MAXSUM;
else
sum = (sumhi << PNG_HISHIFT) + sumlo;
}
#endif
if (sum < mins)
{
mins = sum;
best_row = png_ptr->sub_row;
}
}
/* up filter */
if (filter_to_do == PNG_FILTER_UP)
{
png_bytep rp, dp, pp;
png_uint_32 i;
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) & 0xff);
}
best_row = png_ptr->up_row;
}
else if (filter_to_do & PNG_FILTER_UP)
{
png_bytep rp, dp, pp;
png_uint_32 sum = 0, lmins = mins;
png_uint_32 i;
int v;
#if defined(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_UP)
{
lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >>
PNG_WEIGHT_SHIFT;
}
}
lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
PNG_COST_SHIFT;
lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >>
PNG_COST_SHIFT;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -