public static byte[] DecodePredictor(byte[] inp, PdfObject dicPar) {
if (dicPar == null || !dicPar.IsDictionary())
return inp;
PdfDictionary dic = (PdfDictionary)dicPar;
PdfObject obj = GetPdfObject(dic.Get(PdfName.PREDICTOR));
if (obj == null || !obj.IsNumber())
return inp;
int predictor = ((PdfNumber)obj).IntValue;
if (predictor < 10)
return inp;
int width = 1;
obj = GetPdfObject(dic.Get(PdfName.COLUMNS));
if (obj != null && obj.IsNumber())
width = ((PdfNumber)obj).IntValue;
int colors = 1;
obj = GetPdfObject(dic.Get(PdfName.COLORS));
if (obj != null && obj.IsNumber())
colors = ((PdfNumber)obj).IntValue;
int bpc = 8;
obj = GetPdfObject(dic.Get(PdfName.BITSPERCOMPONENT));
if (obj != null && obj.IsNumber())
bpc = ((PdfNumber)obj).IntValue;
MemoryStream dataStream = new MemoryStream(inp);
MemoryStream fout = new MemoryStream(inp.Length);
int bytesPerPixel = colors * bpc / 8;
int bytesPerRow = (colors*width*bpc + 7)/8;
byte[] curr = new byte[bytesPerRow];
byte[] prior = new byte[bytesPerRow];
// Decode the (sub)image row-by-row
while (true) {
// Read the filter type byte and a row of data
int filter = 0;
try {
filter = dataStream.ReadByte();
if (filter < 0) {
return fout.ToArray();
}
int tot = 0;
while (tot < bytesPerRow) {
int n = dataStream.Read(curr, tot, bytesPerRow - tot);
if (n <= 0)
return fout.ToArray();
tot += n;
}
} catch {
return fout.ToArray();
}
switch (filter) {
case 0: //PNG_FILTER_NONE
break;
case 1: //PNG_FILTER_SUB
for (int i = bytesPerPixel; i < bytesPerRow; i++) {
curr[i] += curr[i - bytesPerPixel];
}
break;
case 2: //PNG_FILTER_UP
for (int i = 0; i < bytesPerRow; i++) {
curr[i] += prior[i];
}
break;
case 3: //PNG_FILTER_AVERAGE
for (int i = 0; i < bytesPerPixel; i++) {
curr[i] += (byte)(prior[i] / 2);
}
for (int i = bytesPerPixel; i < bytesPerRow; i++) {
curr[i] += (byte)(((curr[i - bytesPerPixel] & 0xff) + (prior[i] & 0xff))/2);
}
break;
case 4: //PNG_FILTER_PAETH
for (int i = 0; i < bytesPerPixel; i++) {
curr[i] += prior[i];
}
for (int i = bytesPerPixel; i < bytesPerRow; i++) {
int a = curr[i - bytesPerPixel] & 0xff;
int b = prior[i] & 0xff;
int c = prior[i - bytesPerPixel] & 0xff;
int p = a + b - c;
int pa = Math.Abs(p - a);
int pb = Math.Abs(p - b);
int pc = Math.Abs(p - c);
int ret;
if ((pa <= pb) && (pa <= pc)) {
ret = a;
} else if (pb <= pc) {
ret = b;
} else {
ret = c;
}
curr[i] += (byte)(ret);
}
break;
default:
// Error -- uknown filter type
throw new Exception("PNG filter unknown.");
}
fout.Write(curr, 0, curr.Length);
// Swap curr and prior
byte[] tmp = prior;
prior = curr;
curr = tmp;
}
}