Rust编程入门 阅读代码 - 一个项目例子:解析BMP位图文件

前言

不是本人项目,只是 Github 看到的,很适合入门学习,所以写下这篇文章

BMP 格式帧

image

BMP取自位图Bitmap的缩写,也称为DIB(与设备无关的位图),是一种独立于显示器的位图数字图像文件格式。常见于微软视窗和OS/2操作系统,Windows GDI API内部使用的DIB数据结构与 BMP 文件格式几乎相同。

图像通常保存的颜色深度有2(1位)、16(4位)、256(8位)、65536(16位)和1670万(24位)种颜色(其中位是表示每点所用的数据位)。8位图像可以是索引彩色图像外,也可以是灰阶图像。表示透明的alpha通道也可以保存在一个类似于灰阶图像的独立文件中。带有集成的alpha通道的32位版本已经随着Windows XP出现,它在视窗的登录和主题系统中都有使用。

感性理解一下

image

开始阅读代码(解码部分)

源码在 src 目录里,测试例子在 example 目录。
image

我们要先看 解析bmp格式文件,看一下文件列表,那么肯定是 decoder.rs
image

解析-位图文件头

WIKI: 这部分数据块位于文件开头,用于进行文件的识别。典型的应用程序会首先普通读取这部分数据以确保的确是位图文件并且没有损坏。所有的整数值都以小端序存放(即最低有效位前置)。
image
注:1字节 = 8Bits

L87 调用 read_bmp_id(bmp_data)?; 读取魔数

这个魔数用于确定这是一个BMP文件
这里只适配了最常见的 BM
image

L88 调用 let header = read_bmp_header(bmp_data)?; 读取剩下文件头的部分

image

注:这里的 bmp_data是Cursor<Vec<u8>>类型的,适配着BMP格式的 8bits 小端流。 read_u32之类的是通过 https://docs.rs/byteorder/latest/byteorder/trait.ReadBytesExt.html 实现的
image

解析-DIB头

image

L89 调用 let dib_header = read_bmp_dib_header(bmp_data)?;

image
image

匹配 Bmp版本

image
其中 BmpVersion::from_dib_header 的实现如下
image
对应着数据帧里的版本格式
image

匹配 像素格式(每像素有多少个比特

image
像素信息是在前面的Dib头解析过的,在这里只是做一下判断处理
image

匹配 压缩类型

image
其中 CompressionType 源码如下
image

对应着帧数据格式的
image

最后返回dib结果

image

附加位掩码

image

解析 调色板

image

image

L91 解析 let color_palette = read_color_palette(bmp_data, &dib_header)?;

image

解析像素

解析出像素数组并用于调用 fn read_indexes(

image

对应着
image

其中用于读取索引的函数 fn read_indexes( 源码如下
image

用于读取像素数据的函数 fn read_pixels( 源码如下
image

最后构造出整个BMP文件数据帧的结构体/内存形态

image
对应开头的 BMP 格式帧
image
注:填充区就是用于保持内存/结构体对齐的,即填充一些无用数据,保持内存对齐,这样不会降低硬件的读取速度(硬件一般都需要数据对齐才能保持最佳的速度
这个项目采用通用解法,即解析时根据偏移跳过填充区,因为读取填充区没有意义,我们只需要读取的时候能对齐就行。

阅读代码(编码部分)

比较清晰了然,直接上图
image
image
其中 Image 结构体如下
image

写入到文件
image

项目总结

image

  • src 目录

    • decoder.rs 和 encoder.rs 是解码和编码的
    • consts.rs 是颜色集
      image
    • lib.rs 里面,还有一堆测试代码
      image
  • test 目录里是测试资源,例如 lib.rs 里的测试代码就会读取这里的测试图片

  • example 目录里是一个 main 函数例子

类似的项目

https://gitlab.scd31.com/stephen/dtmf

posted @ 2021-12-31 13:55  蓝天上的云℡  阅读(499)  评论(0编辑  收藏  举报