1. 程式人生 > >BMP影象資料格式詳解以及簡單案例

BMP影象資料格式詳解以及簡單案例

一.簡介

BMP(Bitmap-File)圖形檔案是Windows採用的圖形檔案格式,在Windows環境下執行的所有圖象處理軟體都支援BMP圖象檔案格式。Windows系統內部各影象繪製操作都是以BMP為基礎的。Windows 3.0以前的BMP圖檔案格式與顯示裝置有關,因此把這種BMP圖象檔案格式稱為裝置相關點陣圖DDB(device-dependent bitmap)檔案格式。Windows 3.0以後的BMP圖象檔案與顯示裝置無關,因此把這種BMP圖象檔案格式稱為裝置無關點陣圖DIB(device-independent bitmap)格式(注:Windows 3.0以後,在系統中仍然存在DDB點陣圖,象BitBlt()這種函式就是基於DDB點陣圖的,只不過如果你想將影象以BMP格式儲存到磁碟檔案中時,微軟極力推薦你以DIB格式儲存),目的是為了讓Windows能夠在任何型別的顯示裝置上顯示所儲存的圖象。BMP點陣圖檔案預設的副檔名是BMP或者bmp(有時它也會以.DIB或.RLE作副檔名)。

二.BMP格式結構

BMP檔案的資料按照從檔案頭開始的先後順序分為四個部分:

◆ 點陣圖檔案頭(bmp file header)  提供檔案的格式、大小等資訊

◆ 點陣圖資訊頭(bitmap information)提供影象資料的尺寸、位平面數、壓縮方式、顏色索引等資訊

◆ 調色盤(color palette)可選,如使用索引來表示影象,調色盤就是索引與其對應的顏色的對映表

◆ 點陣圖資料(bitmap data)影象資料區

BMP圖片檔案資料表如下:

資料段名稱

大小(byte)

開始地址

結束地址

點陣圖檔案頭(bitmap-file header)

14

0000h

000Dh

點陣圖資訊頭(bitmap-information header)

40

000Eh

0035h

調色盤(color table)

由biBitCount決定

0036h

未知

圖片點陣資料(bitmap data)

由圖片大小和顏色定

未知

未知

三.BMP檔案頭

BMP檔案頭結構體定義如下:

typedef struct tagBITMAPFILEHEADER

UINT16 bfType;        //2Bytes,必須為"BM",即0x424D 才是Windows點陣圖檔案

DWORD bfSize;         //4Bytes,整個BMP檔案的大小

UINT16 bfReserved1;  //2Bytes,保留,為0

UINT16 bfReserved2;  //2Bytes,保留,為0

DWORD bfOffBits;     //4Bytes,檔案起始位置到影象畫素資料的位元組偏移量

BITMAPFILEHEADER;

 

BMP檔案頭資料表如下:

變數名

地址偏移

大小

作用說明

bfType

0000h

2Bytes

檔案識別符號,必須為"BM",即0x424D 才是Windows點陣圖檔案

‘BM’:Windows 3.1x, 95, NT,…  ‘BA’:OS/2 Bitmap Array  ‘CI’:OS/2 Color Icon   

‘CP’:OS/2 Color Pointer   ‘IC’:OS/2 Icon   

‘PT’:OS/2 Pointer

因為OS/2系統並沒有被普及開,所以在程式設計時,你只需判斷第一個標識“BM”就行

bfSize

0002h

4Bytes

整個BMP檔案的大小(以位B為單位)

bfReserved1

0006h

2Bytes

保留,必須設定為0

bfReserved2

0008h

2Bytes

保留,必須設定為0

bfOffBits

000Ah

4Bytes

說明從檔案頭0000h開始到影象畫素資料的位元組偏移量(以位元組Bytes為單位),以為點陣圖的調色盤長度根據點陣圖格式不同而變化,可以用這個偏移量快速從檔案中讀取影象資料

四.BMP資訊頭

BMP資訊頭結構體定義如下:

typedef struct _tagBMP_INFOHEADER

{

DWORD  biSize;    //4Bytes,INFOHEADER結構體大小,存在其他版本I NFOHEADER,用作區分

LONG   biWidth;    //4Bytes,影象寬度(以畫素為單位)

LONG   biHeight;    //4Bytes,影象高度,+:影象儲存順序為Bottom2Top,-:Top2Bottom

WORD   biPlanes;    //2Bytes,影象資料平面,BMP儲存RGB資料,因此總為1

WORD   biBitCount;         //2Bytes,影象畫素位數

DWORD  biCompression;     //4Bytes,0:不壓縮,1:RLE8,2:RLE4

DWORD  biSizeImage;       //4Bytes,4位元組對齊的影象資料大小

LONG   biXPelsPerMeter;   //4 Bytes,用象素/米表示的水平解析度

LONG   biYPelsPerMeter;   //4 Bytes,用象素/米表示的垂直解析度

DWORD  biClrUsed;          //4 Bytes,實際使用的調色盤索引數,0:使用所有的調色盤索引

DWORD biClrImportant;     //4 Bytes,重要的調色盤索引數,0:所有的調色盤索引都重要

}BMP_INFOHEADER;

 

BMP資訊頭資料表如下:

變數名

地址偏移

大小

作用說明

biSize

000Eh

4Bytes

BNP資訊頭即BMP_INFOHEADER結構體所需要的位元組數(以位元組為單位)

biWidth

0012h

4Bytes

說明影象的寬度(以畫素為單位)

biHeight

0016h

4Bytes

說明影象的高度(以畫素為單位)。這個值還有一個用處,指明影象是正向的點陣圖還是倒向的點陣圖,該值是正數說明影象是倒向的即影象儲存是由下到上;該值是負數說明影象是倒向的即影象儲存是由上到下。大多數BMP點陣圖是倒向的點陣圖,所以此值是正值。

biPlanes

001Ah

2Bytes

為目標裝置說明位面數,其值總設定為1

biBitCount

001Ch

2Bytes

說明一個畫素點佔幾位(以位元位/畫素位單位),其值可為1,4,8,16,24或32

biCompression

001Eh

4Bytes

說明影象資料的壓縮型別,取值範圍為:

0         BI_RGB 不壓縮(最常用)

1         BI_RLE8 8位元遊程編碼(BLE),只用於8位點陣圖

2         BI_RLE4 4位元遊程編碼(BLE),只用於4位點陣圖

3         BI_BITFIELDS位元域(BLE),只用於16/32位點陣圖

4          

biSizeImage

0022h

4Bytes

說明影象的大小,以位元組為單位。當用BI_RGB格式時,總設定為0

biXPelsPerMeter

0026h

4Bytes

說明水平解析度,用畫素/米表示,有符號整數

biYPelsPerMeter

002Ah

4Bytes

說明垂直解析度,用畫素/米表示,有符號整數

biClrUsed

002Eh

4Bytes

說明點陣圖實際使用的調色盤索引數,0:使用所有的調色盤索引

biClrImportant

0032h

4Bytes

說明對影象顯示有重要影響的顏色索引的數目,如果是0,表示都重要。

六.BMP調色盤

BMP調色盤結構體定義如下:

typedef struct _tagRGBQUAD

{

BYTE  rgbBlue;       //指定藍色強度

BYTE  rgbGreen;      //指定綠色強度

BYTE  rgbRed;        //指定紅色強度

 BYTE  rgbReserved;  //保留,設定為0

RGBQUAD;

 

1,4,8點陣圖像才會使用調色盤資料,16,24,32點陣圖像不需要調色盤資料,即調色盤最多隻需要256項(索引0 - 255)。

顏色表的大小根據所使用的顏色模式而定:2色影象為8位元組;16色影象位64位元組;256色影象為1024位元組。其中,每4位元組表示一種顏色,並以B(藍色)、G(綠色)、R(紅色)、alpha(32位點陣圖的透明度值,一般不需要)。即首先4位元組表示顏色號1的顏色,接下來表示顏色號2的顏色,依此類推。

顏色表中RGBQUAD結構資料的個數有biBitCount來確定,當biBitCount=1,4,8時,分別有2,16,256個表項。

當biBitCount=1時,為2色影象,BMP點陣圖中有2個數據結構RGBQUAD一個調色盤佔用4位元組資料,所以2色影象的調色盤長度為2*4為8位元組。

當biBitCount=4時,為16色影象,BMP點陣圖中有16個數據結構RGBQUAD一個調色盤佔用4位元組資料,所以16像的調色盤長度為16*4為64位元組。

當biBitCount=8時,為256色影象,BMP點陣圖中有256個數據結構RGBQUAD一個調色盤佔用4位元組資料,所以256色影象的調色盤長度為256*4為1024位元組。

當biBitCount=16,24或32時,沒有顏色表。

五.BMP影象資料區

點陣圖資料記錄了點陣圖的每一個畫素值,記錄順序是在掃描行內是從左到右,掃描行之間是從下到上。點陣圖的一個畫素值所佔的位元組數:

當biBitCount=1時,8個畫素佔1個位元組;

當biBitCount=4時,2個畫素佔1個位元組;

當biBitCount=8時,1個畫素佔1個位元組;

當biBitCount=24時,1個畫素佔3個位元組;

Windows規定一個掃描行所佔的位元組數必須是4的倍數(即以long為單位),不足的以0填充,

一個掃描行所佔的位元組數計算方法:

DataSizePerLine= (biWidth* biBitCount+31)/8;

// 一個掃描行所佔的位元組數

DataSizePerLine= DataSizePerLine/4*4; // 位元組數必須是4的倍數

點陣圖資料的大小(不壓縮情況下):

DataSize= DataSizePerLine* biHeight;

 

顏色表接下來位為點陣圖檔案的影象資料區,在此部分記錄著每點畫素對應的顏色號,其記錄方式也隨顏色模式而定,既2色影象每點佔1位(8位為1位元組);16色影象每點佔4位(半位元組);256色影象每點佔8位(1位元組);真彩色影象每點佔24位(3位元組)。所以,整個資料區的大小也會隨之變化。究其規律而言,可的出如下計算公式:影象資料資訊大小=(影象寬度*影象高度*記錄畫素的位數)/8。

8點陣圖簡單例子:

typedef unsigned char LBYTE;
typedef unsigned short LWORD;
typedef unsigned int LDWORD;
typedef long LLONG;
#pragma pack(2)
typedef struct
{
 LWORD bfType;    //點陣圖檔案型別,必須是0X4D42
 LDWORD bfSize;    // 點陣圖檔案大小
 LWORD bfReserved1;        //windows保留字
 LWORD bfReserved2;        //windows保留字,暫時不用
 LDWORD bfOffBits;   //從檔案頭到實際的點陣圖資料的偏移位元組數
}LBITMAPFILEHEADER;

 

typedef struct
{
 LDWORD biSize;     //點陣圖資訊頭的長度,40位元組
 LLONG biWidth;     //點陣圖的寬度
 LLONG biHeight;     //點陣圖的高度
 LWORD biPlanes;     //目標裝置級別,必須為1
 LWORD biBitCount;    // 每個畫素所佔位數(bit),二值影象為1,灰度影象為8,真彩色影象為24
 LDWORD biCompression;  //  點陣圖壓縮型別
 LDWORD biSizeImage;   // 實際的點陣圖資料佔用的位元組數
 LLONG biXPelsPerMeter;  //指定目標裝置的水平解析度
 LLONG biYPelsPerMeter;  //指定目標裝置的垂直解析度
 LDWORD biClrUsed;    // 點陣圖實際用到的顏色數
 LDWORD biClrImportant;  // 點陣圖顯示過程中重要的顏色數
}LBITMAPINFOHEADER;

typedef struct
{
 LBYTE rgbBlue;        //藍色分量
 LBYTE rgbGreen;       //綠色分量
 LBYTE rgbRed;         //紅色分量
 LBYTE rgbReserved;    //保留位元組,暫時不用
}LRGBQUAD;

void SaveBmp(char * fileName, unsigned char *imgBuffer, int imWidth, int imHeight)
{
 if (!imgBuffer)
 {
  return;
 }
 int biBitCount = 8;
 int colorTablesize = 1024; //灰度影象顏色表
 int lineByte = (imWidth * biBitCount / 8 + 3) / 4 * 4;
 FILE *fp = fopen(fileName, "wb");
 if (!fp)
 {
  return;
 }
 LBITMAPFILEHEADER filehead;
 filehead.bfType = 0x4D42;
 filehead.bfSize = sizeof(LBITMAPFILEHEADER)+sizeof(LBITMAPINFOHEADER)+
  colorTablesize + lineByte * imHeight;
 filehead.bfReserved1 = 0;
 filehead.bfReserved2 = 0;
 filehead.bfOffBits = sizeof(LBITMAPFILEHEADER)+sizeof(LBITMAPINFOHEADER)+colorTablesize;
 //寫點陣圖檔案頭進檔案
 int count = sizeof(LBITMAPFILEHEADER);
 fwrite(&filehead, count, 1, fp);

 

 //申請點陣圖檔案資訊頭結構變數, 填寫檔案資訊頭資訊
 LBITMAPINFOHEADER infoHead;
 infoHead.biBitCount = biBitCount;
 infoHead.biClrImportant = 0;
 infoHead.biClrUsed = 0;
 infoHead.biSize = sizeof(LBITMAPINFOHEADER);
 infoHead.biWidth = imWidth;
 infoHead.biHeight = imHeight;
 infoHead.biPlanes = 1;
 infoHead.biCompression = 0;
 infoHead.biSizeImage = lineByte * imHeight;
 infoHead.biXPelsPerMeter = 0;
 infoHead.biYPelsPerMeter = 0;
 count = sizeof(LBITMAPINFOHEADER);
 fwrite(&infoHead, count, 1, fp);

 

 LRGBQUAD *pColorTable = (LRGBQUAD*)malloc(sizeof(LRGBQUAD)*256);

 

 for (int i = 0; i < 256; i++)
 {
  pColorTable[i].rgbBlue = i;
  pColorTable[i].rgbGreen = i;
  pColorTable[i].rgbRed = i;
  //pColorTable[i].rgbReserved = 0;
 }
 count = sizeof(LRGBQUAD);
 fwrite(pColorTable, count, 256, fp);

 


 //寫點陣圖資料進檔案
 fwrite(imgBuffer, imHeight*lineByte, 1, fp);

 fclose(fp);
 free(pColorTable);
 return 1;
}