| 5229 | } |
| 5230 | |
| 5231 | static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, |
| 5232 | const LodePNGColorMode* info, const LodePNGEncoderSettings* settings) |
| 5233 | { |
| 5234 | /* |
| 5235 | For PNG filter method 0 |
| 5236 | out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are |
| 5237 | the scanlines with 1 extra byte per scanline |
| 5238 | */ |
| 5239 | |
| 5240 | unsigned bpp = lodepng_get_bpp(info); |
| 5241 | /*the width of a scanline in bytes, not including the filter type*/ |
| 5242 | size_t linebytes = (w * bpp + 7) / 8; |
| 5243 | /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/ |
| 5244 | size_t bytewidth = (bpp + 7) / 8; |
| 5245 | const unsigned char* prevline = 0; |
| 5246 | unsigned x, y; |
| 5247 | unsigned error = 0; |
| 5248 | LodePNGFilterStrategy strategy = settings->filter_strategy; |
| 5249 | |
| 5250 | /* |
| 5251 | There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard: |
| 5252 | * If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e. |
| 5253 | use fixed filtering, with the filter None). |
| 5254 | * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is |
| 5255 | not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply |
| 5256 | all five filters and select the filter that produces the smallest sum of absolute values per row. |
| 5257 | This heuristic is used if filter strategy is LFS_MINSUM and filter_palette_zero is true. |
| 5258 | |
| 5259 | If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed, |
| 5260 | but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum |
| 5261 | heuristic is used. |
| 5262 | */ |
| 5263 | if(settings->filter_palette_zero && |
| 5264 | (info->colortype == LCT_PALETTE || info->bitdepth < 8)) strategy = LFS_ZERO; |
| 5265 | |
| 5266 | if(bpp == 0) return 31; /*error: invalid color type*/ |
| 5267 | |
| 5268 | if(strategy == LFS_ZERO) |
| 5269 | { |
| 5270 | for(y = 0; y < h; y++) |
| 5271 | { |
| 5272 | size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/ |
| 5273 | size_t inindex = linebytes * y; |
| 5274 | out[outindex] = 0; /*filter type byte*/ |
| 5275 | filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, 0); |
| 5276 | prevline = &in[inindex]; |
| 5277 | } |
| 5278 | } |
| 5279 | else if(strategy == LFS_MINSUM) |
| 5280 | { |
| 5281 | /*adaptive filtering*/ |
| 5282 | size_t sum[5]; |
| 5283 | ucvector attempt[5]; /*five filtering attempts, one for each filter type*/ |
| 5284 | size_t smallest = 0; |
| 5285 | unsigned type, bestType = 0; |
| 5286 | |
| 5287 | for(type = 0; type < 5; type++) |
| 5288 | { |
no test coverage detected