我正在写一个PNG解码器,我遇到了一些奇怪的事情。通过PNG文件格式,我设法正确解码了具有Color Index + tRNS(alpha)和True Color + tRNS(alpha)的PNG。我目前还不确定为什么我不能用Alpha型PNG解码带有真彩色的PNG。我已经证实我的IDAT块的膨胀是正确的。这是块的样子:
Width: 256
Height: 256
Bit Depth: 8
Color Type: 6
Compression: 0
Filter: 0
Interlace: 0
Length: 25
Type: tEXt
Data: 53 6f 66 74 77 61 72 65 00 41 64 6f 62 65 20 49 6d 61 67 65 52 65 61 64 79
CRC: 71c9653c
Length: 20690
Type: IDAT
Data: 78 da ec 7d 09 9c 1c 57 99 df f7 7a a6 e7 3e 5a a3 fb ...
CRC: 21550259
实际数据太长,无法在此处打印。这是我解码这个的逻辑,如果我错了,请纠正我:
由于这是彩色类型6,因此像素由RGBA通道表示,每个通道1个字节。这意味着我们需要一次解释4个字节。使用以下代码:
ByteBuffer image = BufferUtil.getDirectByteBuffer(data.length, ByteOrder.BIG_ENDIAN);
int i = 0;
while(i < data.length){
int color = ( (data[i] & 0xff) << 24) | ( (data[i+1] & 0xff) << 16) | ( (data[i+2] & 0xff) << 8) | (data[i+3] & 0xff);
image.putInt(color);
i += 4;
奇怪的是,我得到的主要是RRGGBBAA = 0x00000000数据,导致图像清晰,色彩很少。
答案 0 :(得分:1)
问题是你忽略了观察每条扫描线的过滤。
从提供的图像中,解压缩的数据看起来像
1 ffffffff 0 0 0 ...
2 0 0 0 0 0 0 ...
..
每行中的第一个值符合使用的过滤方法[http://www.w3.org/TR/PNG/#9Filters]
扫描线后处理将如下所示
ffffffff ffffffff ffffffff ...
ffffffff ffffffff ffffffff ...
...
这是一些处理方法0,1和2的示例代码。
private static void processScanLine(byte filterValue, byte[] scanLine, byte[] previousScanLine) {
switch(filterValue){
case 0:break;
case 1:
for (int i =4;i<scanLine.length;i++){
scanLine[i] = (byte)(scanLine[i]+scanLine[i-4]);
}
break;
case 2:
for (int i =0;i<scanLine.length;i++){
scanLine[i] = (byte)(scanLine[i]+previousScanLine[i]);
}
break;
}
}