|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
*/ |
|
|
|
package com.sun.imageio.plugins.png; |
|
|
|
public class RowFilter { |
|
|
|
private static final int abs(int x) { |
|
return (x < 0) ? -x : x; |
|
} |
|
|
|
|
|
protected static int subFilter(byte[] currRow, |
|
byte[] subFilteredRow, |
|
int bytesPerPixel, |
|
int bytesPerRow) { |
|
int badness = 0; |
|
for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { |
|
int curr = currRow[i] & 0xff; |
|
int left = currRow[i - bytesPerPixel] & 0xff; |
|
int difference = curr - left; |
|
subFilteredRow[i] = (byte)difference; |
|
|
|
badness += abs(difference); |
|
} |
|
|
|
return badness; |
|
} |
|
|
|
|
|
protected static int upFilter(byte[] currRow, |
|
byte[] prevRow, |
|
byte[] upFilteredRow, |
|
int bytesPerPixel, |
|
int bytesPerRow) { |
|
int badness = 0; |
|
for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { |
|
int curr = currRow[i] & 0xff; |
|
int up = prevRow[i] & 0xff; |
|
int difference = curr - up; |
|
upFilteredRow[i] = (byte)difference; |
|
|
|
badness += abs(difference); |
|
} |
|
|
|
return badness; |
|
} |
|
|
|
protected final int paethPredictor(int a, int b, int c) { |
|
int p = a + b - c; |
|
int pa = abs(p - a); |
|
int pb = abs(p - b); |
|
int pc = abs(p - c); |
|
|
|
if ((pa <= pb) && (pa <= pc)) { |
|
return a; |
|
} else if (pb <= pc) { |
|
return b; |
|
} else { |
|
return c; |
|
} |
|
} |
|
|
|
public int filterRow(int colorType, |
|
byte[] currRow, |
|
byte[] prevRow, |
|
byte[][] scratchRows, |
|
int bytesPerRow, |
|
int bytesPerPixel) { |
|
|
|
|
|
if (colorType != PNGImageReader.PNG_COLOR_PALETTE) { |
|
System.arraycopy(currRow, bytesPerPixel, |
|
scratchRows[0], bytesPerPixel, |
|
bytesPerRow); |
|
return 0; |
|
} |
|
|
|
int[] filterBadness = new int[5]; |
|
for (int i = 0; i < 5; i++) { |
|
filterBadness[i] = Integer.MAX_VALUE; |
|
} |
|
|
|
{ |
|
int badness = 0; |
|
|
|
for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { |
|
int curr = currRow[i] & 0xff; |
|
badness += curr; |
|
} |
|
|
|
filterBadness[0] = badness; |
|
} |
|
|
|
{ |
|
byte[] subFilteredRow = scratchRows[1]; |
|
int badness = subFilter(currRow, |
|
subFilteredRow, |
|
bytesPerPixel, |
|
bytesPerRow); |
|
|
|
filterBadness[1] = badness; |
|
} |
|
|
|
{ |
|
byte[] upFilteredRow = scratchRows[2]; |
|
int badness = upFilter(currRow, |
|
prevRow, |
|
upFilteredRow, |
|
bytesPerPixel, |
|
bytesPerRow); |
|
|
|
filterBadness[2] = badness; |
|
} |
|
|
|
{ |
|
byte[] averageFilteredRow = scratchRows[3]; |
|
int badness = 0; |
|
|
|
for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { |
|
int curr = currRow[i] & 0xff; |
|
int left = currRow[i - bytesPerPixel] & 0xff; |
|
int up = prevRow[i] & 0xff; |
|
int difference = curr - (left + up)/2;; |
|
averageFilteredRow[i] = (byte)difference; |
|
|
|
badness += abs(difference); |
|
} |
|
|
|
filterBadness[3] = badness; |
|
} |
|
|
|
{ |
|
byte[] paethFilteredRow = scratchRows[4]; |
|
int badness = 0; |
|
|
|
for (int i = bytesPerPixel; i < bytesPerRow + bytesPerPixel; i++) { |
|
int curr = currRow[i] & 0xff; |
|
int left = currRow[i - bytesPerPixel] & 0xff; |
|
int up = prevRow[i] & 0xff; |
|
int upleft = prevRow[i - bytesPerPixel] & 0xff; |
|
int predictor = paethPredictor(left, up, upleft); |
|
int difference = curr - predictor; |
|
paethFilteredRow[i] = (byte)difference; |
|
|
|
badness += abs(difference); |
|
} |
|
|
|
filterBadness[4] = badness; |
|
} |
|
|
|
int minBadness = filterBadness[0]; |
|
int filterType = 0; |
|
|
|
for (int i = 1; i < 5; i++) { |
|
if (filterBadness[i] < minBadness) { |
|
minBadness = filterBadness[i]; |
|
filterType = i; |
|
} |
|
} |
|
|
|
if (filterType == 0) { |
|
System.arraycopy(currRow, bytesPerPixel, |
|
scratchRows[0], bytesPerPixel, |
|
bytesPerRow); |
|
} |
|
|
|
return filterType; |
|
} |
|
} |