首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> VC 教學

BMP 位圖文件結構深度解析與平滑縮放技術實現

     編輯:VC 教學

前言

在 Windows 程式設計中,BMP(Bitmap)作為最基礎的圖像格式,雖然結構簡單,但若採用傳統 GDI 方式載入顯示,往往面臨記憶體佔用大、繪圖速度慢、縮放失真嚴重等問題,尤其在低色深裝置上顯示高色深圖像時,色彩失真更為明顯。本文將系統剖析 BMP 文件結構,並介紹如何利用視訊函數(Video Functions)實現高效、無失真的位圖顯示與平滑縮放。

一、BMP 文件整體架構

標準 BMP 文件由四大部分依序組成:

  1. 位圖文件頭(Bitmap File Header)
  2. 位圖資訊頭(Bitmap Info Header)
  3. 調色盤/顏色表(Color Table / Palette)
  4. 像素資料區(Bitmap Data / Pixel Array)

其中前三部分統稱為「位圖資訊」,僅像素資料區大小隨圖像尺寸與色深變化。

二、關鍵結構體詳細定義

1. BITMAPFILEHEADER - 文件頭(14 位元組)

typedef struct tagBITMAPFILEHEADER {
    WORD  bfType;      // 檔案類型,必須為 'BM' (0x4D42)
    DWORD bfSize;      // 檔案總大小(位元組)
    WORD  bfReserved1; // 保留,必須為 0
    WORD  bfReserved2; // 保留,必須為 0
    DWORD bfOffBits;   // 像素資料起始偏移量(相對文件開頭)
} BITMAPFILEHEADER;

bfOffBits 是定位像素資料的關鍵,讀取時直接 Seek 到此位置即可開始解碼。

2. BITMAPINFOHEADER - 資訊頭(40 位元組,Windows BITMAPINFOHEADER 標準版)

typedef struct tagBITMAPINFOHEADER {
    DWORD biSize;           // 結構體大小,固定 40
    LONG  biWidth;          // 圖像寬度(像素),正數
    LONG  biHeight;         // 圖像高度(像素),正數=底部優先,負數=頂部優先
    WORD  biPlanes;         // 色板數,固定 1
    WORD  biBitCount;       // 色深:1/4/8/16/24/32
    DWORD biCompression;    // 壓縮類型:BI_RGB(0), BI_RLE8(1), BI_RLE4(2), BI_BITFIELDS(3)
    DWORD biSizeImage;      // 像素資料大小(可為 0 表示未壓縮)
    LONG  biXPelsPerMeter;  // 水平解析度
    LONG  biYPelsPerMeter;  // 垂直解析度
    DWORD biClrUsed;        // 實際使用的調色盤索引數
    DWORD biClrImportant;   // 重要顏色數(0 表示全部重要)
} BITMAPINFOHEADER;

注意:biHeight 為負值時表示採用「頂部優先」儲存順序(Top-down DIB),此時無需翻轉即可直接繪製。

3. RGBQUAD - 調色盤條目(4 位元組)

typedef struct tagRGBQUAD {
    BYTE rgbBlue;     // 藍色分量 0-255
    BYTE rgbGreen;    // 綠色分量 0-255
    BYTE rgbRed;      // 紅色分量 0-255
    BYTE rgbReserved; // 保留,必須為 0
} RGBQUAD;

調色盤條目數由 biBitCount 決定:

  • 1-bit → 2 色(單色)
  • 4-bit → 16 色
  • 8-bit → 256 色
  • 16/24/32-bit → 無調色盤,像素直接儲存 RGB 值

4. BITMAPINFO - 綜合資訊結構

typedef struct tagBITMAPINFO {
    BITMAPINFOHEADER bmiHeader;
    RGBQUAD          bmiColors[1]; // 柔性陣列,實際大小由 biClrUsed 決定
} BITMAPINFO;

三、像素資料儲存細節與行對齊

BMP 採用 4 位元組邊界對齊:每行像素資料長度必須是 4 的倍數,不足者以 0x00 填充。計算公式:

行寬位元組數 = ((biWidth * biBitCount + 31) / 32) * 4

儲存順序預設為 從下往上(Bottom-up),即文件中第一行像素對應圖像最底行。若 biHeight < 0 則為從上往下。

四、視訊函數實現高效顯示與平滑縮放

傳統 StretchBlt 縮放品質較差。利用 DirectDraw / Direct2D / GDI+ 等視訊介面,可發揮 GPU 硬體加速:

  • 建立離屏 Surface / Bitmap,一次性將解碼後的像素上傳至顯存。
  • 使用硬體雙線性/雙三次插值進行縮放,消除鋸齒與色彩失真。
  • 支援 YUV/RGB 格式轉換,在低色深裝置上自動抖動,保真度遠超 GDI。
  • 非同步傳輸,不阻塞 UI 執行緒,大圖載入流暢無卡頓。

五、程式碼片段:核心載入邏輯(偽代碼)

// 1. 讀取文件頭與資訊頭
BITMAPFILEHEADER fh; BITMAPINFOHEADER ih;
fread(&fh, 1, sizeof(fh), fp);
fread(&ih, 1, sizeof(ih), fp);

// 2. 讀取調色盤(若有)
RGBQUAD *palette = nullptr;
if (ih.biBitCount <= 8) {
    int nColors = (ih.biClrUsed ? ih.biClrUsed : (1 << ih.biBitCount));
    palette = new RGBQUAD[nColors];
    fread(palette, sizeof(RGBQUAD), nColors, fp);
}

// 3. 定位像素資料並一次性讀入
fseek(fp, fh.bfOffBits, SEEK_SET);
int stride = ((ih.biWidth * ih.biBitCount + 31) >> 5) << 2;
BYTE *bits = new BYTE[stride * abs(ih.biHeight)];
fread(bits, 1, stride * abs(ih.biHeight), fp);

// 4. 建立 DIBSection 或直接上傳至 GPU 紋理
// ... 後續交由 Direct2D/GDI+ 繪製與縮放

六、總結

掌握 BMP 結構是圖形程式設計的基礎;結合現代視訊 API,可輕鬆解決記憶體、速度、失真三大痛點,實現專業級圖像瀏覽與編輯體驗。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved