带 Alpha 解码的 PNG 真彩色

Posted

技术标签:

【中文标题】带 Alpha 解码的 PNG 真彩色【英文标题】:PNG True color with Alpha decoding 【发布时间】:2014-07-04 04:23:49 【问题描述】:

我正在编写一个 PNG 解码器,但遇到了一些奇怪的问题。通过 PNG 文件格式,我成功地使用颜色索引 + 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

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

    膨胀 IDAT 块中给定的所有字节 取消过滤膨胀块。在这种情况下,所有过滤器的类型都是 0,因此,我们只需丢弃过滤器字节。

    因为这是颜色类型 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 数据,导致图像清晰,颜色很少。

【问题讨论】:

【参考方案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;
    

【讨论】:

你解压压缩数据的短样本sn-p了吗? OP 断言“所有过滤器都是 0 型”。 解压前的二进制数据:dropbox.com/s/20j10fuburid4sy/pre_inflate_data.dat解压后的二进制数据:dropbox.com/s/x35k5df3rpx0tqi/post_inflate_data.dat解压后的一些样本:00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ... 所以看起来过滤字节是0x0。 似乎在前几行扫描之后,过滤器代码可以是非零的。抱歉打扰了。 上一个扫描线和当前扫描线之前的扫描线有什么区别? 我使用发布的图像来测试代码。假设那是正在显示的那个。

以上是关于带 Alpha 解码的 PNG 真彩色的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Perl 和 GD 创建透明的真彩色 PNG?

png文件是啥格式?

免费在线生成彩色带logo的个性二维码

如何使用 PNG 的 IDAT 块?

如何在MFC中加载真彩色的图像资源啊

终端 Emacs 中的真彩色(24 位)