PNG 解压缩 IDAT 块。如何阅读?
PNG decompressed IDAT chunk. How to read?
我已经阅读了太多次 PNG 规范,但仍然对如何解释 IDAT 块感到困惑。我使用 zlib 对其进行了解压缩,并获得了我的 IDAT 块获得的所有字节。
我使用 krita 制作了示例图像。这是一个 3x2 PNG 图像,每个像素包含不同的颜色。
See the 3 by 2 PNG image here
根据关于过滤器的PNG specification,它说当 IDAT 块的第一个字节为 1 时,应用的过滤器方法是
过滤(字节)=原始(字节)-原始(previous_byte)
考虑到该公式,我解压缩了我的 IDAT 块(长度为 29 个字节,仅存储 6 个像素)。第一个字节(字节编号 0)包含值 1。这就是公式的来源。
Byte# Vaue
0 1
1 224
2 215
3 200
4 227
5 241
6 48
7 2
8 36
9 225
10 1
11 253
12 255
13 195
14 245
15 182
16 244
17 232
18 245
19 57
20 0
21 0
22 0
23 0
24 0
25 0
26 0
27 0
28 0
第一个像素应该是我用 RGB to color converter 重建的 RGB(224, 215, 200)。这看起来与图像中原始像素的颜色几乎相同。这是我对所有颜色像素的看法。
Pixel 1: RGB(224, 215, 200) [read from byte 1, byte2 and byte3]
Pixel 2: RGB(195, 200, 248) [because byte 4:227 byte5:241 byte6:48]
Pixel 3: RGB(197, 236, 217) [because byte 7:2 byte8:36 byte9:225]
Pixel 4: RGB(198, 233, 217) [because byte10:1 byte11:253 byte12:255]
Pixel 5: RGB(137, 222, 142) [because byte13:195 byte14:245 byte15:182]
Pixel 6: RGB(107, 198, 131) [because byte16:244 byte17:232 byte18:245]
我已经使用公式从像素中获取所有值。
重建像素 1、2 和 3 看起来几乎相同,但像素 4、5 和 6 不是我所期望的。我想我没有以正确的方式阅读 IDAT 块。这可以解释为什么只有 6 个像素的 RGB 有 29 个字节。我期望 19 个字节,因为 3 乘以 6 是 18 和 1 个字节用于过滤方法。
IHDR说bit depth是8,color type是2。从table中规格说明每个像素都是 R、G 和 B 三元组。有人能给我指出正确的方向来阅读 IDAT 块并解释它的长度吗?
您的解压结果长度29不正确,可能导致您混淆。
您的图像是 3x2 RGB 像素。那将是 3*3 * 2 = 18 个字节的数据,加上每行 1 个额外的字节;一共20个字节。不知何故你得到了额外的 9 个虚拟字节,而不是压缩数据的一部分。
(我从较大的图像重建了你的小图像,很高兴得到了完全相同的数字,否则解释必然是纯粹的理论。为方便起见,我用十六进制查看器确定了压缩数据的偏移量。)
>>> with open ('3x2b.png','rb') as f:
... result = f.seek (0x6a)
... data = f.read()
...
>>> d = zlib.decompress(data)
>>> print ([x for x in d])
[1, 224, 215, 200, 227, 241, 48, 2, 36, 225, 1, 253, 255, 195, 245, 182, 244, 232, 245, 57]
这'unpacks'到以下两行,每行3个RGB像素值:
filter RGB RGB RGB
1 (224,215,200) (227,241,48) (2,36,225)
1 (253,255,195) (245,182,244, (232,245,57)
所有这些值可能相对于较早的结果:在它之前读取的最后一个完整行,或其左侧的像素。对于第一行,您必须假定一行全为零;第一个像素的值 "left" 也必须假定为 0
。
你看到标记为 'filter' 的两个字节了吗?那是你出错的地方。每行都有自己的过滤字节。您使用过滤器字节本身来计算第二行。
添加("Sub" 过滤器的逆运算,如过滤器 1
所示)产生
; start of row 0, filter is 1 and 'initial pixel' is (0,0,0)
(224,215,200) (224+227,215+241,200+48)
=(195,200,248)
(195+2,200+36,248+225)
=(197,236,217)
; restart for row 1, filter is 1 again and start value (0,0,0):
(253,255,195) (253+245,255+182,195+244)
=(242,181,183)
(242+232,181+245,183+57)
=(218,170,240)
...正是我开始使用的颜色。
这是过滤器 1 ("Sub"),因此使用其左侧的值;对于过滤器 2 ("Up"),您需要使用先前解码的 行中的相应字节,对于 Average 和 Paeth,您需要两者。
我已经阅读了太多次 PNG 规范,但仍然对如何解释 IDAT 块感到困惑。我使用 zlib 对其进行了解压缩,并获得了我的 IDAT 块获得的所有字节。
我使用 krita 制作了示例图像。这是一个 3x2 PNG 图像,每个像素包含不同的颜色。 See the 3 by 2 PNG image here
根据关于过滤器的PNG specification,它说当 IDAT 块的第一个字节为 1 时,应用的过滤器方法是
过滤(字节)=原始(字节)-原始(previous_byte)
考虑到该公式,我解压缩了我的 IDAT 块(长度为 29 个字节,仅存储 6 个像素)。第一个字节(字节编号 0)包含值 1。这就是公式的来源。
Byte# Vaue
0 1
1 224
2 215
3 200
4 227
5 241
6 48
7 2
8 36
9 225
10 1
11 253
12 255
13 195
14 245
15 182
16 244
17 232
18 245
19 57
20 0
21 0
22 0
23 0
24 0
25 0
26 0
27 0
28 0
第一个像素应该是我用 RGB to color converter 重建的 RGB(224, 215, 200)。这看起来与图像中原始像素的颜色几乎相同。这是我对所有颜色像素的看法。
Pixel 1: RGB(224, 215, 200) [read from byte 1, byte2 and byte3]
Pixel 2: RGB(195, 200, 248) [because byte 4:227 byte5:241 byte6:48]
Pixel 3: RGB(197, 236, 217) [because byte 7:2 byte8:36 byte9:225]
Pixel 4: RGB(198, 233, 217) [because byte10:1 byte11:253 byte12:255]
Pixel 5: RGB(137, 222, 142) [because byte13:195 byte14:245 byte15:182]
Pixel 6: RGB(107, 198, 131) [because byte16:244 byte17:232 byte18:245]
我已经使用公式从像素中获取所有值。 重建像素 1、2 和 3 看起来几乎相同,但像素 4、5 和 6 不是我所期望的。我想我没有以正确的方式阅读 IDAT 块。这可以解释为什么只有 6 个像素的 RGB 有 29 个字节。我期望 19 个字节,因为 3 乘以 6 是 18 和 1 个字节用于过滤方法。
IHDR说bit depth是8,color type是2。从table中规格说明每个像素都是 R、G 和 B 三元组。有人能给我指出正确的方向来阅读 IDAT 块并解释它的长度吗?
您的解压结果长度29不正确,可能导致您混淆。
您的图像是 3x2 RGB 像素。那将是 3*3 * 2 = 18 个字节的数据,加上每行 1 个额外的字节;一共20个字节。不知何故你得到了额外的 9 个虚拟字节,而不是压缩数据的一部分。
(我从较大的图像重建了你的小图像,很高兴得到了完全相同的数字,否则解释必然是纯粹的理论。为方便起见,我用十六进制查看器确定了压缩数据的偏移量。)
>>> with open ('3x2b.png','rb') as f:
... result = f.seek (0x6a)
... data = f.read()
...
>>> d = zlib.decompress(data)
>>> print ([x for x in d])
[1, 224, 215, 200, 227, 241, 48, 2, 36, 225, 1, 253, 255, 195, 245, 182, 244, 232, 245, 57]
这'unpacks'到以下两行,每行3个RGB像素值:
filter RGB RGB RGB
1 (224,215,200) (227,241,48) (2,36,225)
1 (253,255,195) (245,182,244, (232,245,57)
所有这些值可能相对于较早的结果:在它之前读取的最后一个完整行,或其左侧的像素。对于第一行,您必须假定一行全为零;第一个像素的值 "left" 也必须假定为 0
。
你看到标记为 'filter' 的两个字节了吗?那是你出错的地方。每行都有自己的过滤字节。您使用过滤器字节本身来计算第二行。
添加("Sub" 过滤器的逆运算,如过滤器 1
所示)产生
; start of row 0, filter is 1 and 'initial pixel' is (0,0,0)
(224,215,200) (224+227,215+241,200+48)
=(195,200,248)
(195+2,200+36,248+225)
=(197,236,217)
; restart for row 1, filter is 1 again and start value (0,0,0):
(253,255,195) (253+245,255+182,195+244)
=(242,181,183)
(242+232,181+245,183+57)
=(218,170,240)
...正是我开始使用的颜色。
这是过滤器 1 ("Sub"),因此使用其左侧的值;对于过滤器 2 ("Up"),您需要使用先前解码的 行中的相应字节,对于 Average 和 Paeth,您需要两者。