📄 pngwutil.c
字号:
/* if interlaced, go to next pass */
if (png_ptr->interlaced)
{
png_ptr->row_number = 0;
if (png_ptr->transformations & PNG_INTERLACE)
{
png_ptr->pass++;
}
else
{
/* loop until we find a non-zero width or height pass */
do
{
png_ptr->pass++;
if (png_ptr->pass >= 7)
break;
png_ptr->usr_width = (png_ptr->width +
png_pass_inc[png_ptr->pass] - 1 -
png_pass_start[png_ptr->pass]) /
png_pass_inc[png_ptr->pass];
png_ptr->num_rows = (png_ptr->height +
png_pass_yinc[png_ptr->pass] - 1 -
png_pass_ystart[png_ptr->pass]) /
png_pass_yinc[png_ptr->pass];
if (png_ptr->transformations & PNG_INTERLACE)
break;
} while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0);
}
/* reset the row above the image for the next pass */
if (png_ptr->pass < 7)
{
if (png_ptr->prev_row)
png_memset(png_ptr->prev_row, 0,
(((png_uint_32)png_ptr->usr_channels *
(png_uint_32)png_ptr->usr_bit_depth *
png_ptr->width + 7) >> 3) + 1);
return;
}
}
/* if we get here, we've just written the last row, so we need
to flush the compressor */
do
{
/* tell the compressor we are done */
ret = deflate(png_ptr->zstream, Z_FINISH);
/* check for an error */
if (ret != Z_OK && ret != Z_STREAM_END)
{
if (png_ptr->zstream->msg)
png_error(png_ptr, png_ptr->zstream->msg);
else
png_error(png_ptr, "zlib error");
}
/* check to see if we need more room */
if (!png_ptr->zstream->avail_out && ret == Z_OK)
{
png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
png_ptr->zstream->next_out = png_ptr->zbuf;
png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
}
} while (ret != Z_STREAM_END);
/* write any extra space */
if (png_ptr->zstream->avail_out < png_ptr->zbuf_size)
{
png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size -
png_ptr->zstream->avail_out);
}
deflateReset(png_ptr->zstream);
}
#if defined(PNG_WRITE_INTERLACING_SUPPORTED)
/* pick out the correct pixels for the interlace pass.
The basic idea here is to go through the row with a source
pointer and a destination pointer (sp and dp), and copy the
correct pixels for the pass. As the row gets compacted,
sp will always be >= dp, so we should never overwrite anything.
See the default: case for the easiest code to understand.
*/
void
png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass)
{
/* we don't have to do anything on the last pass (6) */
if (row && row_info && pass < 6)
{
/* each pixel depth is handled seperately */
switch (row_info->pixel_depth)
{
case 1:
{
png_bytep sp;
png_bytep dp;
int shift;
int d;
int value;
png_uint_32 i;
dp = row;
d = 0;
shift = 7;
for (i = png_pass_start[pass];
i < row_info->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;
dp = row;
shift = 6;
d = 0;
for (i = png_pass_start[pass];
i < row_info->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;
dp = row;
shift = 4;
d = 0;
for (i = png_pass_start[pass];
i < row_info->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;
int 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_info->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 given by the application, and then writes the row out with the
* chosen filter */
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;
int bpp;
/* 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 = 0xffffffff;
/* the prediction method we use is to find which method provides
the smallest value when summing the abs of the distances from
zero using anything >= 128 as negitive numbers. */
/* 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 (png_ptr->do_filter & PNG_FILTER_NONE &&
png_ptr->do_filter != PNG_FILTER_NONE)
{
png_bytep rp;
png_uint_32 sum = 0;
int i, v;
for (i = 0, rp = row_buf + 1; i < row_info->rowbytes; i++, rp++)
{
v = *rp;
sum += (v < 128) ? v : 256 - v;
}
mins = sum;
}
/* sub filter */
if (png_ptr->do_filter & PNG_FILTER_SUB)
{
png_bytep rp, dp, lp;
png_uint_32 sum = 0;
int i, v;
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 < mins)
{
mins = sum;
best_row = png_ptr->sub_row;
}
}
/* up filter */
if (png_ptr->do_filter & PNG_FILTER_UP)
{
png_bytep rp, dp, pp;
png_uint_32 sum = 0;
int i, v;
for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1,
pp = prev_row + 1; i < row_info->rowbytes; i++, rp++, pp++, dp++)
{
v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
sum += (v < 128) ? v : 256 - v;
}
if (sum < mins)
{
mins = sum;
best_row = png_ptr->up_row;
}
}
/* avg filter */
if (png_ptr->do_filter & PNG_FILTER_AVG)
{
png_bytep rp, dp, pp, lp;
png_uint_32 sum = 0;
int i, v;
for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1,
pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++)
{
v = *dp = (png_byte)(((int)*rp - ((int)*pp / 2)) & 0xff);
sum += (v < 128) ? v : 256 - v;
}
for (lp = row_buf + 1; i < row_info->rowbytes;
i++, rp++, pp++, lp++, dp++)
{
v = *dp = (png_byte)(((int)*rp - (((int)*pp + (int)*lp) / 2)) & 0xff);
sum += (v < 128) ? v : 256 - v;
}
if (sum < mins)
{
mins = sum;
best_row = png_ptr->avg_row;
}
}
/* paeth filter */
if (png_ptr->do_filter & PNG_FILTER_PAETH)
{
png_bytep rp, dp, pp, cp, lp;
png_uint_32 sum = 0;
int i, v;
for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1,
pp = prev_row + 1; i < bpp; i++, rp++, pp++, dp++)
{
v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff);
sum += (v < 128) ? v : 256 - v;
}
for (lp = row_buf + 1, cp = prev_row + 1; i < row_info->rowbytes;
i++, rp++, pp++, lp++, dp++, cp++)
{
int a, b, c, pa, pb, pc, p;
b = *pp;
c = *cp;
a = *lp;
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;
v = *dp = (png_byte)(((int)*rp - p) & 0xff);
sum += (v < 128) ? v : 256 - v;
}
if (sum < mins)
{
best_row = png_ptr->paeth_row;
}
}
/* Do the actual writing of the filtered row data from the chosen filter */
png_write_filtered_row(png_ptr, best_row);
}
/* do the actual writing of a filtered row */
void
png_write_filtered_row(png_structp png_ptr, png_bytep filtered_row)
{
/* set up the zlib input buffer */
png_ptr->zstream->next_in = filtered_row;
png_ptr->zstream->avail_in = (uInt)png_ptr->row_info.rowbytes + 1;
/* repeat until we have compressed all the data */
do
{
int ret; /* return of zlib */
/* compress the data */
ret = deflate(png_ptr->zstream, Z_NO_FLUSH);
/* check for compression errors */
if (ret != Z_OK)
{
if (png_ptr->zstream->msg)
png_error(png_ptr, png_ptr->zstream->msg);
else
png_error(png_ptr, "zlib error");
}
/* see if it is time to write another IDAT */
if (!png_ptr->zstream->avail_out)
{
/* write the IDAT and reset the zlib output buffer */
png_write_IDAT(png_ptr, png_ptr->zbuf, png_ptr->zbuf_size);
png_ptr->zstream->next_out = png_ptr->zbuf;
png_ptr->zstream->avail_out = (uInt)png_ptr->zbuf_size;
}
/* repeat until all data has been compressed */
} while (png_ptr->zstream->avail_in);
/* swap the current and previous rows */
if (png_ptr->prev_row)
{
png_bytep tptr;
tptr = png_ptr->prev_row;
png_ptr->prev_row = png_ptr->row_buf;
png_ptr->row_buf = tptr;
}
/* finish row - updates counters and flushes zlib if last row */
png_write_finish_row(png_ptr);
#if defined(PNG_WRITE_FLUSH_SUPPORTED)
png_ptr->flush_rows++;
if (png_ptr->flush_dist > 0 &&
png_ptr->flush_rows >= png_ptr->flush_dist)
{
png_write_flush(png_ptr);
}
#endif /* PNG_WRITE_FLUSH_SUPPORTED */
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -