話說,上禮拜下了個決心,那就是寫一個封裝的程式,就是把一堆圖檔音樂什麼鬼的都丟在一個檔案裡面那樣
既然如此,就得深入該檔案的格式和內容了
本來很狂妄的想直接從PNG開始,最終還是不敵英文的猛攻,轉戰最通用也最多資料也最簡單的BMP檔
雖說簡單,但也搞了兩三天,不斷的爬文在爬文,還真是辛苦哪XD
點陣圖檔主要分為四部份:
- 點陣圖標頭檔:點陣圖檔案資訊。
Bitmap Header: stores general information about the bitmap file. - 點陣圖資訊:點陣圖影像的資訊。
Bitmap Information: stores detailed information about the bitmap image. - 調色盤:所用到的顏色資料。
Color Palette: stores the definition of the colors being used. - 點陣圖資料:每個像素的資料。
Bitmap Data: stores the actual image, pixel by pixel.
其中,24位元的圖檔,每個像素都可視為一個調色盤,故沒有調色盤的資料。
以下用程式說明,我覺得比較簡單…
BITMAPFILEHEADER pBmp; // 用來儲存標頭檔的結構
typedef struct tagBITMAPFILEHEADER {
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
BITMAPINFOHEADER pBMIH; // 用來儲存資訊的結構
typedef struct tagBITMAPINFOHEADER{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER
structRGB TempRGB; // 用來儲存點陣圖資料的結構
// 當然要先開一個BMP檔哩!
ifstream infile("data\\Title.bmp", ios_base::in | ios_base::binary);
《點陣圖標頭檔》
// [0~1][WORD] 點陣圖檔案的辨識符號,通常都是 0x42 0x4D ( ‘B‘ & ‘M’)
infile.read(reinterpret_cast<char*>(&pBmp.bfType), sizeof(WORD));// [2~5][DWORD] 整個點陣圖檔案的大小
infile.read(reinterpret_cast<char*>(&pBmp.bfSize), sizeof(DWORD));// [6~7][WORD] & [8~9][WORD] 保留的空間,應該沒啥用
infile.read(reinterpret_cast<char*>(&pBmp.bfReserved1), sizeof(WORD));
infile.read(reinterpret_cast<char*>(&pBmp.bfReserved2), sizeof(WORD));// [10~13][DWORD] 點陣圖標頭+資訊的大小
// 換句話說,檔案開頭的位址 + 這個大小 = 點陣圖資料的起始位址
infile.read(reinterpret_cast<char*>(&pBmp.bfOffBits), sizeof(DWORD));
《點陣圖資訊》
// [14~17][DWORD] 資訊部分的大小
infile.read(reinterpret_cast<char*>(&pBMIH.biSize), sizeof(DWORD));// [18~21][DWORD] 影像的寬度
infile.read(reinterpret_cast<char*>(&pBMIH.biWidth), sizeof(DWORD));// [22~25][DWORD] 影像的高度
infile.read(reinterpret_cast<char*>(&pBMIH.biHeight), sizeof(DWORD));// [26~27][WORD] 色彩面的個數(硬翻的),通常沒在用
infile.read(reinterpret_cast<char*>(&pBMIH.biPlanes), sizeof(WORD));// [28~29][WORD] 每個像素的位元數,也就是色彩深度,通常為 1, 4, 8, 24, 32
infile.read(reinterpret_cast<char*>(&pBMIH.biBitCount), sizeof(WORD));// [30~33][DWORD] 壓縮演算法,未壓縮則為 0,詳請看wiki
infile.read(reinterpret_cast<char*>(&pBMIH.biCompression), sizeof(DWORD));// [34~37][DWORD] 點陣圖影像的大小(和檔案大小不同)
infile.read(reinterpret_cast<char*>(&pBMIH.biSizeImage), sizeof(DWORD));// [38~41][LONG] 水平解析度
// [42~45][LONG] 垂直解析度
infile.read(reinterpret_cast<char*>(&pBMIH.biXPelsPerMeter), sizeof(LONG));
infile.read(reinterpret_cast<char*>(&pBMIH.biYPelsPerMeter), sizeof(LONG));// [46~49][DWORD] 所用顏色的數目
infile.read(reinterpret_cast<char*>(&pBMIH.biClrUsed), sizeof(DWORD));// [50~53][DWORD] 重要顏色的數目,如果都很重要,則與 "所用顏色的數目" 相等
infile.read
(reinterpret_cast<char*>(&pBMIH.biClrImportant), sizeof(DWORD));
到此總共 54 位元,基本上點陣圖檔的標頭+資訊都這麼大
調色盤,目前用途只需要24位元即可,所以省略調色盤~
接著就是最重要的像素資料啦~
24位元的像素資料由 4 個 DWORD 組成,分別為:(保留)、R、G、B,四個值表示如下:
typedef struct
{
DWORD reserve;
DWORD r;
DWORD g;
DWORD b;
}structRGB;
資料參考:
http://www.thethirdmedia.com/pc/200407/20040722117029.shtm
http://www.shengfang.org/blog/p/bmpformat.php
http://zh.wikipedia.org/wiki/BMP
http://en.wikipedia.org/wiki/Windows_and_OS/2_bitmap
http://andrew.csie.ncyu.edu.tw/DOC2/BMP.doc
http://big5.yesky.com/b5/dev.yesky.com/164/2291664.shtml
◎補充:
點陣圖的像素資料儲存的方法是:由下往上,由左往右。
所以第一筆像素資料是在圖片的左下角,會後一筆資料在右上角。