前言
不是本人項目,只是 Github 看到的,很適合入門學習,所以寫下這篇文章
- 當前commit版本:https://github.com/sondrele/rust-bmp/commit/0425dadd43de63f9f89030780f2f3b9fee7e868c
- 在線查看代碼:https://github.dev/sondrele/rust-bmp/blob/master/src/decoder.rs
- BMP 文件的幀數據格式:https://zh.wikipedia.org/wiki/BMP#位圖文件頭
BMP 格式幀
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出現,它在視窗的登錄和主題系統中都有使用。
感性理解一下
開始閱讀代碼(解碼部分)
源碼在 src 目錄裏,測試例子在 example 目錄。
我們要先看 解析bmp格式文件,看一下文件列表,那麼肯定是 decoder.rs
解析-位圖文件頭
WIKI: 這部分數據塊位於文件開頭,用於進行文件的識別。典型的應用程序會首先普通讀取這部分數據以確保的確是位圖文件並且沒有損壞。所有的整數值都以小端序存放(即最低有效位前置)。
注:1字節 = 8Bits
L87 調用 read_bmp_id(bmp_data)?; 讀取魔數
這個魔數用於確定這是一個BMP文件
這裏只適配了最常見的 BM
L88 調用 let header = read_bmp_header(bmp_data)?; 讀取剩下文件頭的部分
注:這裏的 bmp_data是Cursor<Vec<u8>>
類型的,適配着BMP格式的 8bits 小端流。 read_u32之類的是通過 https://docs.rs/byteorder/latest/byteorder/trait.ReadBytesExt.html 實現的
解析-DIB頭
L89 調用 let dib_header = read_bmp_dib_header(bmp_data)?;
匹配 Bmp版本
其中 BmpVersion::from_dib_header 的實現如下
對應着數據幀裏的版本格式
匹配 像素格式(每像素有多少個比特
像素信息是在前面的Dib頭解析過的,在這裏只是做一下判斷處理
匹配 壓縮類型
其中 CompressionType 源碼如下
對應着幀數據格式的
最後返回dib結果
附加位掩碼
解析 調色板
L91 解析 let color_palette = read_color_palette(bmp_data, &dib_header)?;
解析像素
解析出像素數組並用於調用 fn read_indexes(
對應着
其中用於讀取索引的函數 fn read_indexes(
源碼如下
用於讀取像素數據的函數 fn read_pixels(
源碼如下
最後構造出整個BMP文件數據幀的結構體/內存形態
對應開頭的 BMP 格式幀
注:填充區就是用於保持內存/結構體對齊的,即填充一些無用數據,保持內存對齊,這樣不會降低硬件的讀取速度(硬件一般都需要數據對齊才能保持最佳的速度
這個項目採用通用解法,即解析時根據偏移跳過填充區,因爲讀取填充區沒有意義,我們只需要讀取的時候能對齊就行。
閱讀代碼(編碼部分)
比較清晰瞭然,直接上圖
其中 Image 結構體如下
寫入到文件
項目總結
-
src 目錄
-
- decoder.rs 和 encoder.rs 是解碼和編碼的
-
- consts.rs 是顏色集
- consts.rs 是顏色集
-
- lib.rs 裏面,還有一堆測試代碼
- lib.rs 裏面,還有一堆測試代碼
-
test 目錄裏是測試資源,例如 lib.rs 裏的測試代碼就會讀取這裏的測試圖片
-
example 目錄裏是一個 main 函數例子