BMP格式詳解

BMP(全稱Bitmap)是Windows操作系統中的標準圖像文件格式,可以分成兩類:設備相關位圖(DDB)和設備無關位圖(DIB),使用非常廣。它采用位映射存儲格式,除了圖像深度可選以外,不采用其他任何壓縮,因此,BMP文件所占用的空間很大。BMP文件的圖像深度可選lbit、4bit、8bit及24bit。BMP文件存儲數據時,圖像的掃描方式是按從左到右、從下到上的順序。由于BMP文件格式是Windows環境中交換與圖有關的數據的一種標準,因此在Windows環境中運行的圖形圖像軟件都支持BMP圖像格式。

這里通過一個具體的例子對BMP格式做一個簡單的介紹。

1、整體信息

BMP格式的文件從頭到尾依次是如下信息:

  • bmp文件頭(bmp file header):共14字節;
  • 位圖信息頭(bitmap information):共40字節;
  • 調色板(color palette):可選;
  • 位圖數據;
最常見的就是24位圖,所謂的24位圖,就是說一個像素的顏色信息用24位來表示,也就是說,對于三原色BRG,每一個顏色都用以字節(8)位來表示。除了24位圖,還有1位(單色),2位(4色,CGA),4位(16色,VGA),8位(256色),16位(增強色),24位(真彩色)和32位等。

下面通過下面的圖片做詳細介紹:


? 圖像的部分信息如下:


2、bmp文件頭(bmp file header)

bmp文件頭包含如下信息:

  • bfType:2字節,文件類型;
  • bfSize:4字節,文件大小;
  • bfReserved1:2字節,保留,必須設置為0;
  • bfReserved2:2字節,保留,必須設置為0;
  • bfOffBits:4字節,從頭到位圖數據的偏移;
下圖的數據就是bmp文件頭:

一共14字節,下面逐個解釋。
0-1:bfType,表示文件類型,BMP格式的文件這兩個字節是0x4D42,10進制就是19778,字符顯示就是‘BM’;
2-5:bfSize,表示文件的大小,這里的是0x0004B436,十進制是308278,也就是301kb,檢查文件信息,驗證正確;
6-7:bfReserved1,保留位,必須設置為0;
8-9:bfReserved2,保留位,必須設置為0;
a-d:bfOffBits,4字節的偏移,表示從文件頭到位圖數據的偏移,這里是0x00000436,十進制是1078,后面會做驗證;
3、位圖信息頭(bitmap information)
位圖信息頭一共40字節,包含如下內容:
  • biSize:4字節,信息頭的大小,即40;
  • biWidth:4字節,以像素為單位說明圖像的寬度;
  • biHeight:4字節,以像素為單位說明圖像的高度,同時如果為正,說明位圖倒立(即數據表示從圖像的左下角到右上角),如果為負說明正向;
  • biPlanes:2字節,為目標設備說明顏色平面數,總被設置為1;
  • biBitCount:2字節,說明比特數/像素數,值有1、2、4、8、16、24、32;
  • biCompression:4字節,說明圖像的壓縮類型,最常用的就是0(BI_RGB),表示不壓縮;
  • biSizeImages:4字節,說明位圖數據的大小,當用BI_RGB格式時,可以設置為0;
  • biXPelsPerMeter:表示水平分辨率,單位是像素/米,有符號整數;
  • biYPelsPerMeter:表示垂直分辨率,單位是像素/米,有符號整數;
  • biClrUsed:說明位圖使用的調色板中的顏色索引數,為0說明使用所有;
  • biClrImportant:說明對圖像顯示有重要影響的顏色索引數,為0說明都重要;
下圖數據是位圖信息頭:

一共40字節,解釋如下:
0e-11:4字節的biSize,這里是0x28,即十進制的40,驗證正確;
12-15:4字節的biWidth,這里是0x00000280,即十進制的640,用像素表示圖像的寬度,查看文件信息驗證正確;
16-19:4字節的biHeight,這里是0x000001E0,即十進制的480,用像素表示圖像的高度,查看文件信息驗證正確;同時,這是一個正數,表示圖像是倒立的,即圖像數據是從左下角到右上角排列的;
1a-1b:2字節的biPlanes,值為0x0001;
1c-1d:2字節的biBitCount,值是0x0008,即8,表示每個像素用8位表示,一共有256個顏色;
1e-21:4字節的biCompression,值是0,即BI_RGB格式,不壓縮;
22-25:4字節的biSizeImage,圖像的大小,值是0x0004B000,十進制為307200,由上面的bfSize(文件大小)和bfOffBits(文件頭到數據的偏移)分別是308278和1078可以得到,biSizeImage=bfSize-bfOffBits,即圖像大小=文件大小-偏移量;
26-29:4字節的biXPelsPerMeter,水平分辨率,值是0x00000EC4,十進制3780;
2a-2d:4字節的biYPelsPerMeter,垂直分辨率,值是0x00000EC4,十進制3780;
2e-31:4字節的biClrUsed,使用的顏色索引數,值是0x00000100,十進制256,與1c-1d得到的結論一致;
32-35:4字節的biClrImportant,重要的顏色索引數,值是0x00000100,十進制256;
4、調色板(Color Palette)
調色板是可選的,不過這里的8位色圖有調色板。那么接下來的數據就是調色板了。調色板就是一個顏色的索引,這里是8位色圖,一共有256中顏色,由于每個顏色都有RGB三原色,也就是要3個字節表示,這樣的話256個顏色就不能表示所有的顏色,所以就需要一個索引,用一個字節的索引指向4個字節表示的顏色(RGB加上Alpha值)。如果把這4個字節表示為一個Color類型,那么調色板就是Color的數組。由于Color類型也是一個數組,調色板就像一個二維數組palette[N][4],其中N是顏色的數量,這里就是256。因此,這個例子中的調色板的大小就是256x4=1024字節,在調色板之前,有14字節的bmp文件頭,40字節的位圖信息頭,加上1024字節的調色板,一共1078字節,也就是說真正的圖像數據前面有1078字節,這和bmp文件頭中的bfOffBits相符,驗證了我們的討論。
有的圖像沒有調色板,比如下面的24位色圖:

頭部數據如下:

根據上面的討論可以知道,biBitCount是24(0x18),bfOffBits是54(0x36),即沒有調色板,位圖信息頭接下來就是圖像數據了。
調色板中的數據每4字節一組,分別表示藍、綠、紅和Alpha值。按照第一個圖像舉例來說:
索引Alpha
001103700
100104900
200184400
3011D5800
5、位圖數據
接下來就是位圖數據了。由于是8位色圖,所以每個像素用1個字節表示,取出每個字節,顯示到相應的設備上就可以了。
注意,這里的biHeight為正數,說明圖像倒立,從左下角開始到右上角,以行為主序排列。
如果是24位色圖,按照BGR的順序排列,32位色圖按照BGRAlpha排列。
位圖數據排列還有一個規則,就是對齊。
Windows默認的掃描的最小單位是4字節,如果數據對齊滿足這個值的話對于數據的獲取速度等都是有很大的增益的。因此,BMP圖像順應了這個要求,要求每行的數據的長度必須是4的倍數,如果不夠需要進行比特填充(以0填充),這樣可以達到按行的快速存取。這樣的話,位圖數據的大小就不一定是寬x高x每像素字節數了,因為每行還可能有0填充。
填充后的每行數據如下:

其中,BPP是每像素的比特數(Bits Per Pixel),即biBitCount,Width是寬度,單位是像素即bfWidth。
對于我們這個例子,BPP是8,Width是480,正好是4的倍數,也就是沒有填充。來計算一下:
RowSize=4*(8*480/32)=480字節,驗證沒有填充。
那么以上面第二個圖片24位色圖為例,按照數據可以得到:
  • biBitCount=0x0018=24;
  • bfWidth=0x000001c6=454;
  • bfHeight=0x00000053=83;
  • biSizeImage=0x0001BA3c=113212;
按照沒填充計算:454*83*3=113046 bytes,與真實值相差166字節。
按照填充公式,每行有數據4*(24*454/32)=1364 字節,真正的數據有454*3=1362字節,也就是說每行填充了2字節0,一共83行,共填充83*2=166字節,驗證了我們的討論。
在程序中,我們可以用下面的代碼計算每行的數據:
int bytesPerLine=((bfWidth*biBitCount+31)>>5)<<2;
那么,位圖數據大小為:
int imageSize=bytesPerLine*bfHeight;
這樣的話,每掃描完一行數據,最后的幾個字節可能是填充的0,需要跳過:
int skip=4-((bfWidth*biBitCount)>>3)&3;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/385490.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/385490.shtml
英文地址,請注明出處:http://en.pswp.cn/news/385490.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Leetcode 5. 最長回文子串(Longest Palindromic Substring)

推薦理由&#xff1a;暴力解法太 naive&#xff0c;中心擴散不普適&#xff0c;Manacher 就更不普適了&#xff0c;是專門解這個問題的方法。而用動態規劃我認為是最有用的&#xff0c;可以幫助你舉一反三的方法。 補充說明&#xff1a;Manacher 算法有興趣的朋友們可以了解一…

請求轉發與請求重定向的區別

請求轉發&#xff1a; 請求轉發&#xff0c;即request.getRequestDispatcher().forward()&#xff0c;是一種服務器的行為&#xff0c;客戶端只有一次請求&#xff0c;服務器端轉發后會將請求對象保存&#xff0c;地址欄中的URL地址不會改變&#xff0c;得到響應后服務器端再將…

StringBuilder詳解

1、簡介 StringBuilder和StringBuffer一樣&#xff0c;都是繼承自抽象類AbstractStringBuilder類&#xff0c;也是一個可變的字符序列。StringBuilder和StringBuffer非常相似&#xff0c;甚至有互相兼容的API&#xff0c;不過&#xff0c;StringBuilder不是線程安全的&#xf…

【線程】互斥鎖

一、互斥鎖 1. 函數原型 pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict attr); pthread_mutex_destroy(pthread_mutex_t *mutex); 分析&#xff1a; pthread_mutex_t 類型&#xff0c;其本質是一個結構體&#xff0c;為簡化…

ArrayList詳解

1、簡介 ArrayList是Java集合框架中的一個重要的類&#xff0c;它繼承于AbstractList&#xff0c;實現了List接口&#xff0c;是一個長度可變的集合&#xff0c;提供了增刪改查的功能。集合中允許null的存在。ArrayList類還是實現了RandomAccess接口&#xff0c;可以對元素進行…

【進程】進程組

一、進程組 1. 進程組 &#xff08;1&#xff09;進程組&#xff0c;也稱之為作業&#xff0c;BSD與1980年前后向UNIX中增加的一個新特性&#xff0c;代表一個或多個進程的集合。每個進程都屬于一個進程組&#xff0c;在waitpid函數和kill函數的參數中都曾經使用到&#xff0c…

函數wait、waitpid、孤兒進程、僵尸進程

一、函數wait、waitpid 一個進程在終止時會關閉所有文件描述符&#xff0c;釋放在用戶空間釋放的內存&#xff0c;但它的PCB還保留著&#xff0c;內核在其中保存一些信息&#xff1a;如果是正常終止時則保存著退出狀態&#xff0c;如果是異常終止則保存著導致該進程終止的信號是…

MySQL中的字符集與字符序

這篇文章詳細介紹一下MySQL中的字符集和字符序相關的問題&#xff0c;里里外外地了解一下字符集和字符序的方方面面&#xff0c;同時重點說明一下開發中需要注意的問題。 文章基于MySQL 8.0&#xff0c;也會涉及到5.7版本。主要參考MySQL手冊&#xff1a;https://dev.mysql.com…

MySQL中的JSON

從5.7.8開始&#xff0c;MySQL開始支持JSON類型&#xff0c;用于存儲JSON數據。 JSON類型的加入模糊了關系型數據庫與NoSQL之間的界限&#xff0c;給日常開發也帶來了很大的便利。 這篇文章主要介紹一下MySQL中JSON類型的使用&#xff0c;主要參考MySQL手冊&#xff1a;https…

【C++ Primer | 15】虛函數表剖析(一)

一、虛函數 1. 概念 多態指當不同的對象收到相同的消息時&#xff0c;產生不同的動作 編譯時多態&#xff08;靜態綁定&#xff09;&#xff0c;函數重載&#xff0c;運算符重載&#xff0c;模板。運行時多態&#xff08;動態綁定&#xff09;&#xff0c;虛函數機制。為了實現…

【Leetcode | 02】二叉樹、線性表目錄

二叉樹序號題號1 94. 二叉樹的中序遍歷 295. 不同的二叉搜索樹 II396. 不同的二叉搜索樹4 98. 驗證二叉搜索樹 5100. 相同的樹6101. 對稱二叉樹7102. 二叉樹的層次遍歷8103. 二叉樹的鋸齒形層次遍歷9104. 二叉樹的最大深度10105. 從前序與中序遍歷序列構造二叉樹11106. 從中序與…

Leetcode 118. 楊輝三角

給定一個非負整數 numRows&#xff0c;生成楊輝三角的前 numRows 行。 在楊輝三角中&#xff0c;每個數是它左上方和右上方的數的和。 示例: 輸入: 5 輸出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1] ] class Solution { public:vector<vector<int>> generate(…

管道符、重定向與環境變量

輸入輸出重定向 輸入重定向&#xff1a;將文件內容導入到命令中&#xff1b;輸出重定向&#xff1a;將命令執行后顯示到屏幕上的內容導入到文件中&#xff0c;不在屏幕中顯示。共分為&#xff1a;標準輸入重定向&#xff08;文件描述符為0&#xff09;、標準覆蓋輸出&#xff0…

【C++ Primer | 0 】字符串函數實現

1. memcpy函數原型&#xff1a; void* memcpy(void* dst, const void* src, size_t size); void* memmove(void* dst, const void* src, size_t size); 分析&#xff1a; source和destin所指的內存區域可能重疊&#xff0c;但是如果source和destin所指的內存區域重疊,那么這個…

編寫Shell腳本(批處理,一次執行多條命令)

Bash終端的優勢&#xff1a;1.上下鍵重復執行命令&#xff1b;2.tab鍵自動補齊&#xff1b;3.提供有用的環境變量&#xff1b;4.批處理。 shell腳本文件建議以.sh為后綴。 其實vim創建文本文件時&#xff0c;對名字無要求&#xff0c;但最好規定格式。 echo $SHELL&#xff08…

判斷用戶的參數(條件測試語句)

說明$?: $&#xff1f;為上一次命令的執行返回值&#xff0c;若上一次命令正常執行&#xff0c;則返回0&#xff1b;若執行出錯&#xff0c;則返回一個非0的隨機數。比如創建一個已經存在的目錄&#xff0c;則返回一個非0數。 另外&#xff0c;測試語句成立返回0&#xff0c…

流程控制語句(bash)

1.if控制語句 if then fi if then else fi if then elif then elif then else fi if 條件表達式 then 命令序列&#xff08;滿足條件才執行&#xff09; #注意&#xff0c;如果if與then&#xff08;elif與then&#xff09;寫在同一行&#xff0c;要用;隔開&#xff…