英吋 C++

BMP檔解析筆記

話說,上禮拜下了個決心,那就是寫一個封裝的程式,就是把一堆圖檔音樂什麼鬼的都丟在一個檔案裡面那樣
既然如此,就得深入該檔案的格式和內容了
本來很狂妄的想直接從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

還有最重要的 Yahoo!Google !!

◎補充:

點陣圖的像素資料儲存的方法是:由下往上,由左往右。
所以第一筆像素資料是在圖片的左下角,會後一筆資料在右上角。

發表迴響

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Google photo

您的留言將使用 Google 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.