格式組成
典型的BMP圖像檔案由四部分組成:
1:點陣圖頭檔案數據結構,它包含BMP圖像檔案的類型、顯示內容等信息;
2:
點陣圖信息數據結構,它包含有BMP圖像的寬、高、壓縮方法,以及定義顏色等信息;
3:
調色板,這個部分是可選的,有些點陣圖需要調色板,有些點陣圖,比如真彩色圖(24位的BMP)就不需要調色板;
4:點陣圖數據,這部分的內容根據BMP點陣圖使用的位數不同而不同,在24點陣圖中直接使用RGB,而其他的小於24位的使用調色板中顏色索引值。
格式類型
點陣圖一共有兩種類型,即:設備相關點陣圖(DDB)和設備無關點陣圖(DIB)。DDB點陣圖在早期的Windows系統(Windows 3.0以前)中是很普遍的,事實上它也是唯一的。然而,隨著顯示器製造技術的進步,以及顯示設備的多樣化,DDB點陣圖的一些固有的問題開始浮現出來了。比如,它不能夠存儲(或者說獲取)創建這張圖片的原始設備的解析度,這樣,應用程式就不能快速的判斷客戶機的顯示設備是否適合顯示這張圖片。為了解決這一難題,微軟創建了DIB
點陣圖格式。
設備無關點陣圖 (Device-Independent Bitmap)
DIB點陣圖包含下列的顏色和尺寸信息:
* 原始設備(即創建圖片的設備)的顏色格式。
* 原始設備的解析度。
* 原始設備的調色板
* 一個位
數組,由紅、綠、藍(RGB)三個值代表一個像素。
* 一個數組壓縮標誌,用於表明數據的壓縮方案(如果需要的話)。
以上這些信息保存在BITMAPINFO結構中,該結構由BITMAPINFOHEADER結構和兩個或更多個RGBQUAD結構所組成。BITMAPINFOHEADER結構所包含的成員表明了圖像的尺寸、原始設備的顏色格式、以及數據壓縮方案等信息。RGBQUAD結構標識了像素所用到的顏色數據。
DIB點陣圖也有兩種形式,即:底到上型DIB(bottom-up),和頂到下型DIB(top-down)。底到上型DIB的原點(origin)在圖像的左下角,而頂到下型DIB的原點在圖像的左上角。如果DIB的高度值(由BITMAPINFOHEADER結構中的biHeight成員標識)是一個正值,那么就表明這個DIB是一個底到上型DIB,如果高度值是一個負值,那么它就是一個頂到下型DIB。注意:頂到下型的DIB點陣圖是不能被壓縮的。
點陣圖的顏色格式是通過顏色面板值(planes)和顏色位值(bitcount)計算得來的,顏色面板值永遠是1,而顏色位值則可以是1、4、8、16、24、32其中的一個。如果它是1,則表示點陣圖是一張單色點陣圖(譯者註:通常是黑白點陣圖,只有黑和白兩種顏色,當然它也可以是任意兩種指定的顏色),如果它是4,則表示這是一張VGA點陣圖,如果它是8、16、24、或是32,則表示該點陣圖是其他設備所產生的點陣圖。如果應用程式想獲取當前顯示設備(或印表機)的顏色位值(或稱位深度),可調用API函式GetDeviceCaps(),並將第二個參數設為BITSPIXEL即可。
顯示設備的解析度是以每米多少個像素來表明的,應用程式可以通過以下三個步驟來獲取顯示設備或印表機的
水平解析度:
1. 調用GetDeviceCaps()函式,指定第二個參數為HORZRES。
2. 再次調用GetDeviceCaps()函式,指定第二個參數為HORZSIZE。
3. 用第一個返回值除以第二個返回值。即:GetDeviceCaps(hDC,HORZRES)/GetDeviceCaps(hDC,HORZSIZE);
應用程式也可以使用相同的三個步驟來獲取設備的垂直解析度,不同之處只是要將HORZRES替換為VERTRES,把HORZSIZE替換為VERTSIZE,即可。
調色板是被保存在一個RGBQUAD結構的
數組中,該結構指出了每一種顏色的紅、綠、藍的分量值。位數組中的每一個索引都對應於一個調色板項(即一個RGBQUAD結構),應用程式將根據這種對應關係,將像素索引值轉換為像素RGB值(真實的像素顏色)。應用程式也可以通過調用GetDeviceCaps()函式來獲取當前顯示設備的調色板尺寸(將該函式的第二個參數設為NUMCOLORS即可)。
Win32 API支持位數據的壓縮(只對8位和4位的底到上型DIB點陣圖)。壓縮方法是採用運行長度編碼方案(RLE),RLE使用兩個位元組來描述一個句法,第一個位元組表示重複像素的個數,第二個位元組表示重複像素的索引值。有關壓縮點陣圖的詳細信息請參見對BITMAPINFOHEADER結構的解釋。
應用程式可以從一個DDB點陣圖創建出一個DIB點陣圖,步驟是,先初始化一些必要的結構,然後再調用GetDIBits()函式。不過,有些顯示設備有可能不支持這個函式,你可以通過調用GetDeviceCaps()函式來確定一下(GetDeviceCaps()函式在調用時指定RC_DI_BITMAP作為RASTERCAPS的標誌)。
應用程式可以用DIB去設定顯示設備上的像素(譯者註:也就是顯示DIB),方法是調用SetDIBitsToDevice()函式或調用StretchDIBits()函式。同樣,有些顯示設備也有可能不支持以上這兩個函式,這時你可以指定RC_DIBTODEV作為RASTERCAPS標誌,然後調用GetDeviceCaps()函式來判斷該設備是否支持SetDIBitsToDevice()函式。也可以指定RC_STRETCHDIB作為RASTERCAPS標誌來調用GetDeviceCaps()函式,來判斷該設備是否支持StretchDIBits()函式。
如果應用程式只是要簡單的顯示一個已經存在的DIB點陣圖,那么它只要調用SetDIBitsToDevice()函式就可以。比如一個電子表格軟體,它可以打開一個圖表檔案,在視窗中簡單的調用SetDIBitsToDevice()函式,將圖形顯示在視窗中。但如果應用程式要重複的繪製點陣圖的話,則應該使用BitBlt()函式,因為BitBlt()函式的執行速度要比SetDIBitsToDevice()函式快很多。
設備相關點陣圖 (Device-Dependent Bitmaps)
設備相關點陣圖(DDB)之所以現在還被系統支持,只是為了兼容舊的Windows 3.0軟體,如果程式設計師現在要開發一個與點陣圖有關的程式,則應該儘量使用或生成DIB格式的點陣圖。
DDB點陣圖是被一個單個結構BITMAP所描述,這個結構的成員標明了該點陣圖的寬度、高度、設備的顏色格式等信息。
DDB點陣圖也有兩種類型,即:可廢棄的(discardable)DDB和不可廢棄的(nondiscardable)DDB。可廢棄的DDB點陣圖就是一種當
系統記憶體缺乏,並且該點陣圖也沒有被選入設備描述表(DC)的時候,系統就會把該DDB點陣圖從記憶體中清除(即廢棄)。不可廢棄的DDB則是無論系統記憶體多少都不會被系統清除的DDB。API函式CreateDiscardableBitmap()函式可用於創建可廢棄點陣圖。而函式CreateBitmap()、CreateCompatibleBitmap()、和CreateBitmapIndirect()可用於創建不可廢棄的點陣圖。
應用程式可以通過一個DIB點陣圖而創建一個DDB點陣圖,只要先初始化一些必要的結構,然後再調用CreateDIBitmap()函式就可以。如果在調用該函式時指定了CBM_INIT標誌,那么這一次調用就等價於先調用CreateCompatibleBitmap()創建當前設備格式的DDB點陣圖,然後又調用SetDIBits()函式轉換DIB格式到DDB格式。(可能有些設備並不支持SetDIBits()函式,你可以指定RC_DI_BITMAP作為RASTERCAPS的標誌,然後調用GetDeviceCaps()函式來判斷一下)。
對應數據結構
1:BMP檔案組成
2:BMP檔案頭(14位元組)
BMP檔案頭數據結構含有BMP檔案的類型、檔案大小和點陣圖起始位置等信息。
其結構定義如下:
typedef struct tagBITMAPFILEHEADER{ WORD bfType;//點陣圖檔案的類型,必須為BM(1-2位元組) DWORD bfSize;//點陣圖檔案的大小,以位元組為單位(3-6位元組,低位在前) WORD bfReserved1;//點陣圖檔案保留字,必須為0(7-8位元組) WORD bfReserved2;//點陣圖檔案保留字,必須為0(9-10位元組) DWORD bfOffBits;//點陣圖數據的起始位置,以相對於點陣圖(11-14位元組,低位在前) //檔案頭的偏移量表示,以位元組為單位}__attribute__((packed)) BITMAPFILEHEADER;
3:點陣圖信息頭(40位元組)
BMP點陣圖信息頭數據用於說明點陣圖的尺寸等信息。
typedef struct tagBITMAPINFOHEADER{DWORD biSize;//本結構所占用位元組數(15-18位元組)LONG biWidth;//點陣圖的寬度,以像素為單位(19-22位元組)LONG biHeight;//點陣圖的高度,以像素為單位(23-26位元組)WORD biPlanes;//目標設備的級別,必須為1(27-28位元組)WORD biBitCount;//每個像素所需的位數,必須是1(雙色),(29-30位元組)//4(16色),8(256色)16(高彩色)或24(真彩色)之一DWORD biCompression;//點陣圖壓縮類型,必須是0(不壓縮),(31-34位元組)//1(BI_RLE8壓縮類型)或2(BI_RLE4壓縮類型)之一DWORD biSizeImage;//點陣圖的大小(其中包含了為了補齊行數是4的倍數而添加的空位元組),以位元組為單位(35-38位元組)LONG biXPelsPerMeter;//點陣圖水平解析度,每米像素數(39-42位元組)LONG biYPelsPerMeter;//點陣圖垂直解析度,每米像素數(43-46位元組)DWORD biClrUsed;//點陣圖實際使用的顏色表中的顏色數(47-50位元組)DWORD biClrImportant;//點陣圖顯示過程中重要的顏色數(51-54位元組)}__attribute__((packed)) BITMAPINFOHEADER;
4:顏色表
顏色表用於說明點陣圖中的顏色,它有若干個表項,每一個表項是一個RGBQUAD類型的結構,定義一種顏色。RGBQUAD結構的定義如下:
typedef struct tagRGBQUAD{BYTE rgbBlue;//藍色的亮度(值範圍為0-255)BYTE rgbGreen;//綠色的亮度(值範圍為0-255)BYTE rgbRed;//紅色的亮度(值範圍為0-255)BYTE rgbReserved;//保留,必須為0}__attribute__((packed)) RGBQUAD;
顏色表中RGBQUAD結構數據的個數有biBitCount來確定:
當biBitCount=1,4,8時,分別有2,16,256個表項;
當biBitCount=24時,沒有顏色表項。
點陣圖信息頭和顏色表組成點陣圖信息,BITMAPINFO結構定義如下:
typedef struct tagBITMAPINFO{BITMAPINFOHEADER bmiHeader;//點陣圖信息頭RGBQUAD bmiColors[1];//顏色表}__attribute__((packed)) BITMAPINFO;
5:點陣圖數據
點陣圖
數據記錄了點陣圖的每一個像素值,記錄順序是在掃描行內是從左到右,掃描行之間是從下到上。點陣圖的一個像素值所占的位元組數:
當biBitCount=1時,8個像素占1個位元組;
當biBitCount=4時,2個像素占1個位元組;
當biBitCount=8時,1個像素占1個位元組;
當biBitCount=24時,1個像素占3個位元組,按順序分別為B,G,R;
Windows規定一個掃描行所占的位元組數必須是
4的倍數(即以long為單位),不足的以0填充,
biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight;
具體數據舉例:
如某BMP檔案開頭:
4D42 46900000 0000 0000 4600 0000 2800 0000 8000 0000 9000 0000 0100*1000 0300 0000 0090 0000 A00F 0000 A00F0000 0000 00000000 0000*00F8 E007 1F00 0000*02F1 84F1 04F1 84F1 84F1 06F2 84F1 06F2 04F2 86F2 06F2 86F2 86F2 .... ....
讀取方法
/*
功能:在圖片的第50行畫一條黑線
為簡化代碼,只支持24位色的圖片
codeblocks下正確運行。VC下需要將二維數組img改為malloc動態分配。需要添加#include "stdlib.h"。
*/
#include<stdio.h>#include<windows.h>typedef struct{BYTE b;BYTE g;BYTE r;}RGB;int main(void){BITMAPFILEHEADER fileHeader;BITMAPINFOHEADER infoHeader;FILE*pfin=fopen("原始圖像.bmp","rb");FILE*pfout=fopen("修改後的圖像.bmp","wb");//ReadtheBitmapfileheader;fread(&fileHeader,sizeof(BITMAPFILEHEADER),1,pfin);//ReadtheBitmapinfoheader;fread(&infoHeader,sizeof(BITMAPINFOHEADER),1,pfin);//為簡化代碼,只處理24位彩色if(infoHeader.biBitCount==24){int size=infoHeader.biWidth*infoHeader.biHeight;RGB img[infoHeader.biHeight][infoHeader.biWidth]; //這裡有錯誤,尺度改為常量fread(img,sizeof(RGB),size,pfin);//把第50行染成黑色int i=0;for(;i<infoHeader.biWidth;i++){img[50][i].b=img[50][i].g=img[50][i].r=0;}//將修改後的圖片保存到檔案fwrite(&fileHeader,sizeof(fileHeader),1,pfout);fwrite(&infoHeader,sizeof(infoHeader),1,pfout);fwrite(img,sizeof(RGB),size,pfout);}fclose(pfin);fclose(pfout);}
檔案部分
圖像檔案頭
1)1-2:(這裡的數字代表的是位元組,下同)圖像檔案頭。0x4d42=’BM’,表示是Windows支持的
BMP格式。(
注意:查ascii表B 0x42,M0x4d,bfType 為兩個位元組,B為low位元組,M為high位元組所以bfType=0x4D42,而不是0x424D,請注意)
2)3-6:整個檔案大小。4690 0000,為00009046h=36934。
3)7-8:保留,必須設定為0。
4)9-10:保留,必須設定為0。
5)11-14:從檔案開始到點陣圖數據之間的
偏移量(14+40+4*(2^biBitCount))(在有顏色板的情況下)。4600 0000,為00000046h=70,上面的檔案頭就是35字=70位元組。
點陣圖信息頭
6)15-18:點陣圖圖信息頭長度。
7) 19-22:點陣圖寬度,以像素為單位。8000 0000,為00000080h=128。
8)23-26:點陣圖高度,以像素為單位。9000 0000,為00000090h=144。
9)27-28:點陣圖的位面數,該值總是1。0100,為0001h=1。
10)29-30:每個像素的位數。有1(單色),4(16色),8(256色),16(64K色,高彩色),24(16M色,真彩色),32(4096M色,增強型真彩色)。1000為0010h=16。
11)31-34:壓縮說明:有0(不壓縮),1(RLE 8,8位RLE壓縮),2(RLE 4,4位RLE壓縮,3(Bitfields,位域存放)。RLE簡單地說是採用像素數+像素值的方式進行壓縮。T408採用的是位域存放方式,用兩個位元組表示一個像素,位域分配為r5b6g5。圖中0300 0000為00000003h=3(這張圖片不存在顏色板)。
12)35-38:用位元組數表示的點陣圖數據的大小,該數必須是4的倍數,
數值上等於:一行所占的位元組數×點陣圖高度。0090 0000為00009000h=80×90×2h=36864。假設點陣圖是24位,寬為41,高為30,則數值= (biWidth*biBitCount+31)/32*4*biHeight,即=(41*24+31)/32*4*30=3720
13)39-42:用
象素/米表示的
水平解析度。A00F 0000為0000 0FA0h=4000。
14)43-46:用象素/米表示的垂直解析度。A00F 0000為0000 0FA0h=4000。
15)47-50:點陣圖使用的顏色索引數。設為0的話,則說明使用所有調色板項。
16)51-54:對圖象顯示有重要影響的顏色索引的數目。如果是0,表示都重要。
彩色板
17)(55+0)到(50-1+2^biBitCount):彩色板規範。對於調色板中的每個表項,用下述方法來描述RGB的值:
1位元組用於藍色分量
1位元組用於綠色分量
1位元組用於紅色分量
1位元組用於填充符(設定為0)
對於24-位
真彩色圖像就不使用彩色板,因為點陣圖中的RGB值就代表了每個象素的顏色。
如,彩色板為00F8 0000 E007 0000 1F00 0000 0000 0000,其中:
00F8為F800h = 1111 1000 0000 0000(二進制),是藍色分量的掩碼。
E007 為 07E0h = 0000 0111 1110 0000(二進制),是綠色分量的掩碼。
1F00為001Fh = 0000 0000 0001 1111(二進制),是紅色分量的掩碼。
0000 總設定為0。
將掩碼跟像素值進行“與”運算再進行移位操作就可以得到各色分量值。看看掩碼,就可以明白事實上在每個像素值的兩個位元組16位中,按從高到低取5、6、5位分別就是r、g、b分量值。取出分量值後把r、g、b值分別乘以8、4、8就可以補齊第個分量為一個位元組,再把這三個位元組按rgb組合,放入存儲器(同樣要反序),就可以轉換為24位標準BMP格式了。
圖像數據陣列
18)55(無調色板)-bfSize:每兩個位元組表示一個像素。陣列中的第一個位元組表示點陣圖左下角的
象素,而最後一個位元組表示點陣圖右上角的象素。
//----圖像處理-----BMP為DIB類型,從底向上顯示---------
//陣列中的第一個位元組表示點陣圖左下角的象素,而最後一個位元組表示點陣圖右上角的象素。
//下面的代碼可以完成第一個位元組表示點陣圖左上角的象素,而最後一個位元組表示點陣圖右下角的象素,即正常的顯示狀態,便於操作。
int m,n;
unsigned char k;
m = BMPPIC.BMPInfoHead.biWidth/8; //24
n = BMPPIC.BMPInfoHead.biHeight; //96, 24*96 = 2304 bytes
for(int i=0; i < n/2; i++ )
{
for(int a=0; a < m; a++ )
{
k = pbufout1[m*(n-i-1) + a];
pbufout1[m*(n-i-1) + a] = pbufout1[i*m + a];
pbufout1[i*m + a] = k;
}
}
存儲算法
BMP檔案通常是不壓縮的,所以它們通常比同一幅圖像的壓縮圖像檔案格式要大很多。例如,一個800×600的24位幾乎占據1.4MB空間。因此它們通常不適合在網際網路或者其它低速或者有容量限制的媒介上進行傳輸。根據顏色深度的不同,圖像上的一個像素可以用一個或者多個
位元組表示,它由n/8所確定(n是位深度,1位元組包含8個
數據位)。圖片瀏覽器等基於位元組的ASCII值計算像素的顏色,然後從調色板中讀出相應的值。更為詳細的信息請參閱下面關於
點陣圖檔案的部分。n位2n種顏色的點陣圖近似位元組數可以用下面的公式計算:BMP檔案大小約等於 54+4*2的n次方+(w*h*n)/8,其中高度和寬度都是像素數。需要注意的是上面公式中的54是點陣圖檔案的
檔案頭,是彩色調色板的大小。另外需要注意的是這是一個近似值,對於n位的
點陣圖圖像來說,儘管可能有最多2n中顏色,一個特定的圖像可能並不會使用這些所有的顏色。由於彩色
調色板僅僅定義了圖像所用的顏色,所以實際的彩色調色板將小於。如果想知道這些值是如何得到的,請參考下面檔案格式的部分。由於存儲算法本身決定的因素,根據幾個圖像參數的不同計算出的大小與實際的檔案大小將會有一些細小的差別。
數據類型
Oracle產品 EPC Bitmap 中數據類型 EPC bitmap的縮寫。
Oracle提出了一種EPC bitmap的數據類型對基於RFID產品項級別跟蹤套用產生的大量的數據進行有效處理,。
EPC bitmap數據類型定義一個EPC集合,集合共享EPC的一些特徵(例如header,manager number,and object class)。支持這個數據類型的關鍵是使用RFID標識的物品項,在一個群組裡可以基於共同屬性(例如位置,截止日期,或製造商),在通常情況下可以被追蹤。而EPC集合可以表示為一個EPC bitmap,bitmap可以被訪問並可通過epc2bmp或bmp2epc進行數據類型的轉換操作。
引入EPC bitmap(epc bmp)類型的好處:
(1)可以簡單的標識一個RFID EPC集合,而不會丟失任何信息;
(2)對於同類的EPC操作可以簡單的在bitmap上操作,簡化了操作方式
br/