PNG真彩色,带Alpha解码功能

时间:2014-07-04 04:23:50

标签: java png

我正在写一个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

实际数据太长,无法在此处打印。这是我解码这个的逻辑,如果我错了,请纠正我:

  1. 对IDAT块中给出的所有字节进行充气
  2. 取消过滤膨胀的块。在这种情况下,所有过滤器都是0类型,因此,我们只是丢弃过滤器字节。
  3. 由于这是彩色类型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;
    
  4. 奇怪的是,我得到的主要是RRGGBBAA = 0x00000000数据,导致图像清晰,色彩很少。

    Decoded Image

    Original Image

1 个答案:

答案 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;
    }
}