如何將點陣圖物件儲存為BMP檔案
阿新 • • 發佈:2019-01-02
GDI中點陣圖物件是很常見的GDI物件,但是無論是SDK,還是MFC都沒有提供現在的函式或是方法來將一個位圖物件儲存為一個BMP檔案,這裡介紹一下儲存方法。
點陣圖檔案格式:
DIB檔案有四個主要部分:
檔案表頭(BITMAPFILEHEADER)
資訊表頭 (BITMAPINFOHEADER)
調色盤(不一定有)
點陣圖圖素位
而一個位圖物件和上述唯一不同在於它沒有檔案表頭。
相關資料結構:
(1)檔案表頭
指出影象的尺寸
LONG biXPelsPerMeter; //水平基線
LONG biYPelsPerMeter; //堅直基線
DWORD biClrUsed; //被用的顏色數
DWORD biClrImportant; //重要的顏色數
} BITMAPINFOHEADER, *PBITMAPINFOHEADER;
BYTE rgbReserved ; // = 0
}RGBQUAD ;
注意這個結構應該是一個數組,在256色及以下的BMP檔案中存在,陣列的長度關鍵看顏色數。
BITMAP定義了一個位圖的型別、長度、寬度、顏色格式等,這個結構一般用GetObject來獲得。定義如下:typedef struct tagBITMAP {
LONG bmType; //型別,不過總是為0
LONG bmWidth; //寬度,總是大於0
LONG bmHeight; //高度,總是大於0
LONG bmWidthBytes; //MSDN上解釋說是指定每一個掃描行的位元組數。
WORD bmPlanes; //指定調色盤數目
WORD bmBitsPixel; //指示一個畫素所要求的byte位
LPVOID bmBits; //指定一個數組指標,這個陣列大約應該是儲存點陣圖資料的。
} BITMAP, *PBITMAP
一個位圖物件也就是存在記憶體中的點陣圖,它與存在硬碟上的BMP檔案相比,唯一的區別就是它沒有BITMAPFILEHEADER這個檔案資訊頭,其餘部分是完全相同的,所以我們要做的就是先構造一個檔案資訊頭,寫入檔案中,然後將記憶體中的點陣圖寫入檔案。
原始碼如下:(只寫主要部分)
WORD wbitsCount;//點陣圖中每個畫素所佔位元組數。
DWORD dwpalettelsize=0;//調色盤大小
DWORD dwbmdibitsize,dwdibsize,dwwritten;
BITMAP bitmap;//定義了點陣圖的各種的資訊。
BITMAPFILEHEADER bmfhdr;//定義了大小、型別等BMP檔案的資訊。
BITMAPINFOHEADER bi;
LPBITMAPINFOHEADER lpbi;
HANDLE fh,fdib;
GetObject(hBitmap,sizeof(BITMAP),(void *)&bitmap);//得到BITMAP結構。
//以下程式碼是用BITMAP的資訊填充BITMAPINFOHEADER結構
wbitsCount=bitmap.bmBitsPixel;
bi.biSize=sizeof(BITMAPINFOHEADER);
bi.biWidth=bitmap.bmWidth;
bi.biHeight=bitmap.bmHeight;
bi.biPlanes=1;
bi.biBitCount= bitmap.bmBitsPixel ;
bi.biClrImportant=0;
bi.biClrUsed=0;
bi.biCompression=BI_RGB;
bi.biSizeImage=0;
bi.biYPelsPerMeter=0;
bi.biXPelsPerMeter=0;
//以下程式碼是獲取調色盤的長度,調色盤現在的用處很少,因為256色的點陣圖已經不多了。
if(wbitsCount<=8)
dwpalettelsize=(1<<wbitsCount)*sizeof(RGBQUAD);
//計算點陣圖的大小,並分配相應的記憶體空間,注意的是沒有分配BITMAPFILEHEADER。
dwbmdibitsize=((bitmap.bmWidth*wbitsCount+31)/8)*bitmap.bmHeight;
fdib=GlobalAlloc(GHND,dwbmdibitsize+dwpalettelsize+sizeof(BITMAPINFOHEADER));
lpbi=(LPBITMAPINFOHEADER)::GlobalLock(fdib);
*lpbi=bi;//將bi中的資料寫入分配的記憶體中。
hdc=::GetDC(NULL);
GetDIBits(hdc,hBitmap,0,(UINT)bitmap.bmHeight,(LPSTR)lpbi+sizeof(BITMAPINFOHEADER)+dwpalettelsize,(BITMAPINFO *)lpbi,DIB_RGB_COLORS);
/*GetDIBits是最重要的函式,真正獲得點陣圖資料的工作就由它完成,它第一個引數為HDC,第二個引數為點陣圖控制代碼,第三個引數為掃描行的開始行,一般為0,第四個為結束行,一般就是高度,第四個引數最重要,它表示接收資料的起始地址,這個地址一般是在調色盤之後。第五個引數指的是接收BITMAPINFO結構的地址,這個結構上面沒有寫,它其實就是BITMAPINFO結構加上調色盤資訊。最後一個引數是格式。一般是DIB_RGB_COLORS*/
//建立檔案以及檔案資訊頭
fh=CreateFile(FileName,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,FILE_ATTRIBUTE_NORMAL|FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if(fh==INVALID_HANDLE_VALUE)
return FALSE;
bmfhdr.bfType=0x4d42;//BMP型別,一定要這樣寫
dwdibsize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+dwbmdibitsize+dwpalettelsize;//檔案總長,由幾個部分組成
bmfhdr.bfSize=dwdibsize;
bmfhdr.bfReserved1=0;
bmfhdr.bfReserved2=0;
bmfhdr.bfOffBits=(DWORD)sizeof(BITMAPFILEHEADER)+(DWORD)sizeof(BITMAPINFOHEADER)+dwpalettelsize;//點陣圖資料相對於檔案頭的偏移量
//將檔案資訊頭寫入檔案
WriteFile(fh,(LPSTR)&bmfhdr,sizeof(BITMAPFILEHEADER),&dwwritten,NULL);
//將資料寫入檔案,包含BITMAPINFO結構、調色盤、資料
WriteFile(fh,(LPSTR)lpbi,dwdibsize,&dwwritten,NULL);
//關閉相關控制代碼
::GlobalUnlock(fdib);
::GlobalFree(fdib);
::CloseHandle(fh);
return TRUE;
typedef struct tagBITMAPFILEHEADER {
WORD bfType; //BMP檔案型別,總是字元BM,十六進位制為0x4d42
DWORD bfSize; //BMP檔案大小,包含這個結構在內。
WORD bfReserved1;
WORD bfReserved2; //以上均保留為0
DWORD bfOffBits; //是一個偏移量,指出了檔案中圖素位開始位置的位元組偏移量
} BITMAPFILEHEADER, *PBITMAPFILEHEADER;
(2)資訊表頭typedef struct tagBITMAPINFOHEADER{ DWORD biSize; //結構的大小 LONG biWidth; //點陣圖的寬度 LONG biHeight; //點陣圖的高度 WORD biPlanes; //必須是1 WORD biBitCount; //指出每一個畫素要用的bit位。 DWORD biCompression; //指出是否是壓縮的,以及壓縮方式 DWORD biSizeImage; //
(3)調色盤結構:typedef struct tagRGBQUAD // rgb { BYTE rgbBlue ; // blue level BYTE rgbGreen ; // green level BYTE rgbRed ; // red level