📄 pngwutil.c
字号:
} }#ifdef PNG_WRITE_INTERLACING_SUPPORTED /* if interlaced, we need to set up width and height of pass */ if (png_ptr->interlaced) { if (!(png_ptr->transformations & PNG_INTERLACE)) { png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - png_pass_ystart[0]) / png_pass_yinc[0]; png_ptr->usr_width = (png_ptr->width + png_pass_inc[0] - 1 - png_pass_start[0]) / png_pass_inc[0]; } else { png_ptr->num_rows = png_ptr->height; png_ptr->usr_width = png_ptr->width; } } else#endif { png_ptr->num_rows = png_ptr->height; png_ptr->usr_width = png_ptr->width; } png_ptr->zstream.avail_out = (uInt)png_ptr->zbuf_size; png_ptr->zstream.next_out = png_ptr->zbuf;}/* Internal use only. Called when finished processing a row of data. */void /* PRIVATE */png_write_finish_row(png_structp png_ptr){#ifdef PNG_USE_LOCAL_ARRAYS /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* start of interlace block */ int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; /* offset to next interlace block */ int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; /* start of interlace block in the y direction */ int png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; /* offset to next interlace block in the y direction */ int png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2};#endif int ret; png_debug(1, "in png_write_finish_row\n"); /* next row */ png_ptr->row_number++; /* see if we are done */ if (png_ptr->row_number < png_ptr->num_rows) return;#ifdef PNG_WRITE_INTERLACING_SUPPORTED /* 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 != NULL) png_memset(png_ptr->prev_row, 0, (png_size_t) (((png_uint_32)png_ptr->usr_channels * (png_uint_32)png_ptr->usr_bit_depth * png_ptr->width + 7) >> 3) + 1); return; } }#endif /* 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) { /* check to see if we need more room */ if (!(png_ptr->zstream.avail_out)) { 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; } } else if (ret != Z_STREAM_END) { if (png_ptr->zstream.msg != NULL) png_error(png_ptr, png_ptr->zstream.msg); else png_error(png_ptr, "zlib error"); } } 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 /* PRIVATE */png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass){#ifdef PNG_USE_LOCAL_ARRAYS /* arrays to facilitate easy interlacing - use pass (0 - 6) as index */ /* start of interlace block */ int png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; /* offset to next interlace block */ int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1};#endif png_debug(1, "in png_do_write_interlace\n"); /* we don't have to do anything on the last pass (6) */#if defined(PNG_USELESS_TESTS_SUPPORTED) if (row != NULL && row_info != NULL && pass < 6)#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 & 0x07))) & 0x01; 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 & 0x03)) << 1)) & 0x03; 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 & 0x01)) << 2)) & 0x0f; 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 /* PRIVATE */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_b
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -