Png的数据解析

介绍

文档主要是描述获取png字节流,转换像素数据的过程。

大致过程:
1. 获取字节流
2. 解析数据块
3. 解压
4. 过滤
5. 最终像素

png格式

目前解析的是RGBA格式的图片,IHDR数据块显示的过滤方式是0,压缩方式0。其它格式的png,解析过程的差异主要会体现在过滤这个过程。

签名

Png 文件字节流,固定开头。
16进制数据:89 50 4E 47 0D 0A 1A 0A 对应的ASCII 50-P 4E-N 47-G PNG
在这里插入图片描述

数据块

PNG定义了两种类型的数据块,一种是关键数据块,另一种是辅助数据块(可选数据块)。关键数据块定义了4个标准的数据块。既是IHDR,PLTE(调色板数据块),IDAT,IEND。本文解析的图片是RGBA32位的图片,就不介绍PLTE。
在这里插入图片描述

每个数据块格式固定
在这里插入图片描述

  1. IHDR
    文件头数据块IHDR(header chunk,13个字节)包含PNG文件中存储的图像数据的基本信息,包括分辨率、比特深度、色彩模式、压缩方法,是非常重要的数据块,必须作为第一个数据块出现在PNG数据流中,而且一个PNG数据流中只能有一个文件头数据块。
    在这里插入图片描述

下图是 3* 3 图片
在这里插入图片描述

00 00 00 0D 10进制结果:13 chunkData 长度13
49 48 44 52 ASCII IHDR
00 00 00 03 图片宽度 3
00 00 00 03 图片高度 3
08 图片深度 06 颜色类型
00 压缩 00 过滤 00 扫描方法
CRC: 56 28 B5 BF
2. IDAT
生成IDAT需要先经过Filter(具体算法由IHDR指定),再经过Deflate(具体算法由IHDR指定)。这个数据块可以包含多个,但是必须连续。图片显示只包含一个
在这里插入图片描述

00 00 00 1A 长度 -26
49 44 41 54 ASCII IDAT
08 1D 63 64 …00 37 9E 01 9E 一共26个 这块数据包含压缩数据 和前两个标识数据
CRC:9F 19 1D 7E
3. IEND
在这里插入图片描述

数据格式固定
00 00 00 00 49 45 4E 44 AE 42 60 82
00 00 00 00 长度-0
49 45 4E 44 ASCII IEND
AE 42 60 82 CRC

压缩

PNG中的Deflate与gzip、zlib中的deflate原理一样,结合了LZ77和Hoffman算法。
图片显示的压缩方式是 0
具体压缩算法,百度。

        // 使用System.IO.Compression进行Deflate压缩
        public byte[] MicrosoftCompress(byte[] data)
        {
            MemoryStream uncompressed = new MemoryStream(data); // 这里举例用的是内存中的数据;需要对文本进行压缩的话,使用 FileStream 即可
            MemoryStream compressed = new MemoryStream();
            DeflateStream deflateStream = new DeflateStream(compressed, CompressionMode.Compress); // 注意:这里第一个参数填写的是压缩后的数据应该被输出到的地方
            uncompressed.CopyTo(deflateStream); // 用 CopyTo 将需要压缩的数据一次性输入;也可以使用Write进行部分输入
            deflateStream.Close();  // 在Close中,会先后执行 Finish 和 Flush 操作。
            byte[] result = compressed.ToArray();
            return result;
        }

解压

图片显示的压缩方式是 0,所以使用zlib去解压。
解压记得把得到的IDAT 前两位去掉。要不然无法正常解压。有兴趣可以去了解这前两个字节的含义。
解压得到的数据:
在这里插入图片描述

        // 使用System.IO.Compression进行Deflate解压
        public byte[] MicrosoftDecompress(byte[] data)
        {
            MemoryStream compressed = new MemoryStream(data);
            MemoryStream decompressed = new MemoryStream();
            DeflateStream deflateStream = new DeflateStream(compressed, CompressionMode.Decompress); // 注意: 这里第一个参数同样是填写压缩的数据,但是这次是作为输入的数据
            deflateStream.CopyTo(decompressed);
            byte[] result = decompressed.ToArray();
            return result;
        }

解压的数据截图:
33 的图片IDAT解压后得到313 个字节
334(RGBA)+3(每行的过滤方式) =39 个字节
数据读取是从左到右读取,由上到下扫描
每一行的开头 001 002 002 代表每行的过滤方式
在这里插入图片描述

过滤

在这里插入图片描述

在这里插入图片描述

边界值都是0 处理,值大于255需要value%256
a:同行前一个像素相同位置的值
b:前一行同位置的值
c:b位置前一个像素相同位置的值
Filt(x): 过滤后的值
Orig(x): 原值
Recon(a): a 位置的原值
Recon(b): b 位置的原值
floor((Recon(a)+Recon(b))/2): 均值
PaethPredictor(Recon(a),Recon(b),Recon©)
函数逻辑图:
在这里插入图片描述

  1. 过滤0:
    返回过滤值 Filt(x)
  2. 过滤1:
    返回Filt(x)+Recon(a)
  3. 过滤2:
    Filt(x)+Recon(b)
  4. 过滤3:
    Filt(x)+(Recon(a)+recon(b))/2
  5. 过滤4:
    PaethPredictor(Recon(a),Recon(b),Recon©),具体看逻辑图。
    过滤后得到值:
    在这里插入图片描述

得到9个像素值

工具

HxD

参考

https://cloud.tencent.com/developer/article/1857732 数据解析
https://mp.weixin.qq.com/s/XGzuSF-L-qKriyRGcGs-KA Lz77 压缩
https://www.ffutop.com/posts/2019-05-10-png-structure/ 图片解析
https://www.w3.org/TR/2003/REC-PNG-20031110/ png 规范

  • 22
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值