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 函數例子

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章