从零构建PNG:如何将扫描线数据转为无压缩zlib流?
嘿,我来帮你理清楚手动构建无压缩zlib流的字节逻辑——其实拆解开来一点都不复杂,咱们一步步来:
核心逻辑铺垫
首先得明确:zlib流本质是对deflate压缩数据的封装,而你要的“无压缩”,对应deflate里的STORED块(完全不压缩的原始数据块)。所以整个zlib流由三部分组成:zlib头部 + deflate STORED块 + ADLER32校验码。
第一步:构造zlib头部(固定2字节)
头部由CMF和FLG两个字节组成,规则如下:
- CMF(第一个字节):高4位固定为
8(表示使用deflate压缩方法,这是zlib唯一标准的压缩方式);低4位是CINFO(窗口大小参数),对于无压缩的STORED块来说,随便选一个合法值就行,比如设为0,所以CMF最终是0x80(二进制10000000)。 - FLG(第二个字节):必须满足
CMF * 256 + FLG的结果是31的倍数(这是zlib的校验规则)。以CMF=0x80为例,计算得FLG需要是0x1E(因为0x80*256 + 0x1E = 32798,刚好能被31整除)。
第二步:构造deflate STORED块(无压缩数据块)
STORED块是用来直接存放原始扫描线数据的,结构分四部分:
- 块头(1字节):
- 最低位(第0位)设为
1(标记这是最后一个块,PNG的IDAT通常只需要一个块); - 第1-2位设为
00(表示这是STORED无压缩块); - 所以块头最终是
0x01。
- 最低位(第0位)设为
- LEN(2字节):你的扫描线数据的总字节数,用小端字节序存储。比如数据长度是100字节,就写
0x64 0x00。 - NLEN(2字节):LEN的按位取反值,同样用小端字节序存储。比如LEN=100(0x64),取反后低2字节是
0x9C 0xFF。 - 原始数据:直接拼接你的扫描线数据(注意PNG扫描线每行开头有个过滤字节,通常是0,这个你应该已经处理好了)。
第三步:添加ADLER32校验码(固定4字节)
zlib流的最后,需要计算整个deflate块(也就是块头+LEN+NLEN+扫描线数据)的ADLER32校验值,用大端字节序拼在末尾。
如果你不想手动计算ADLER32,可以找现成的在线工具,或者参考zlib库的adler32函数实现。
拼接起来就是完整的zlib流
把上面三部分按顺序拼接:zlib头部(0x80 0x1E) + STORED块 + ADLER32校验码
举个极简例子:假设你的扫描线数据是0x00 0x01 0x02(3字节),最终的zlib流大概是:0x80 0x1E 0x01 0x03 0x00 0xFC 0xFF 0x00 0x01 0x02 [ADLER32值]
最后可以用zlib的uncompress函数测试一下,看能不能正确解压出你的原始扫描线数据,验证是否正确。
内容的提问来源于stack exchange,提问作者StephenKhoa
相关产品推荐
相关产品推荐

