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

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

     編輯:VC 教學

前言

在傳統的 BMP 位圖顯示方式中,常面臨佔用記憶體大、顯示速度慢、縮放失真嚴重,以及在低色深設備上顯示高色深圖像失真等問題。本文將詳細解析 BMP 文件結構,並介紹如何利用視頻函數 DrawDib 實現高效、平滑的位圖縮放顯示,有效解決上述痛點。

一、BMP 文件結構深度解析

1. 文件組成概覽

BMP 文件主要由四大部分組成:文件頭、位圖信息頭、顏色表(調色盤)以及位圖數據。

2. 文件頭

文件頭包含文件類型、大小及數據偏移等核心資訊,結構定義如下:

typedef struct tagBITMAPFILEHEADER {
    WORD  bfType;      // 文件類型,必須為 "BM"
    DWORD bfSize;      // 文件大小(位元組)
    WORD  bfReserved1; // 保留字,必須為 0
    WORD  bfReserved2; // 保留字,必須為 0
    DWORD bfOffBits;   // 位圖數據起始偏移量(相對文件頭)
} BITMAPFILEHEADER;

3. 位圖信息頭

記錄位圖的尺寸、色深、壓縮方式、分辨率等關鍵屬性:

typedef struct tagBITMAPINFOHEADER {
    DWORD biSize;           // 結構體大小
    LONG  biWidth;          // 寬度(像素)
    LONG  biHeight;         // 高度(像素)
    WORD  biPlanes;         // 目標設備平面數,必須為 1
    WORD  biBitCount;       // 每像素位數 (1, 4, 8, 24)
    DWORD biCompression;    // 壓縮類型 (BI_RGB, BI_RLE8, BI_RLE4)
    DWORD biSizeImage;      // 圖像大小(位元組)
    LONG  biXPelsPerMeter;  // 水平分辨率
    LONG  biYPelsPerMeter;  // 垂直分辨率
    DWORD biClrUsed;        // 實際使用顏色數
    DWORD biClrImportant;   // 重要顏色數
} BITMAPINFOHEADER;

4. 顏色表與像素數據

顏色表 由 RGBQUAD 結構組成,定義藍、綠、紅三色分量。當 biBitCount 為 1、4、8 時分別擁有 2、16、256 個表項;24 位真彩色無顏色表。

位圖數據 採用底部優先、從左到右的行順序存儲。Windows 規定每掃描行位元組數必須為 4 的倍數(不足補 0)。計算公式:

DataSizePerLine = (biWidth * biBitCount + 31) / 8;
DataSizePerLine = (DataSizePerLine + 3) & ~3; // 4 字節對齊
DataSize = DataSizePerLine * biHeight;

二、傳統顯示方法及其缺陷

常規流程:GlobalAlloc 分配內存 → 讀取文件 → CreateDIBitmap 創建 DDB → BitBlt/StretchBlt 繪製 → DeleteObject 釋放。

  • 速度慢:涉及設備相關位圖 (DDB) 轉換開銷大。
  • 佔用記憶體大:需同時保留文件緩衝區與 DDB。
  • 縮放失真:StretchBlt 缺乏高質量插值算法。
  • 低色深設備兼容性差:無自動抖動處理,真彩色圖在 256 色模式下嚴重失真。

三、DrawDib 視頻函數:高性能顯示方案

DrawDib 系列 API 屬於 Video for Windows (VFW) 組件,專為高性能圖形繪製設計。

核心優勢

  • 記憶體佔用低:直接操作 DIB 數據,無需創建 DDB。
  • 顯示速度快:利用硬件加速與優化的伸縮算法。
  • 內建抖動:DDF_BACKGROUNDPAL 標誌自動處理高色深到低色深的映射。
  • 縮放質量高:採用雙線性/雙三次插值,縮小時失真極小。

實現流程

  1. 構造函數中調用 DrawDibOpen() 獲取句柄 HDRAWDIB。
  2. 讀取 BMP 文件至內存,解析出 BITMAPINFOHEADER 指針與像素數據偏移。
  3. OnPaint 中調用 DrawDibRealize 實現調色盤,隨後呼叫 DrawDibDraw 繪製。
  4. 析構函數調用 DrawDibClose 釋放資源。

關鍵代碼片段

void CVIEwBitmap::GraphicDraw(void) {
    CClientDC dc(this);
    BITMAPFILEHEADER* pBitmapFileHeader = (BITMAPFILEHEADER*)mpBitsSrc;
    ULONG bfoffBits = pBitmapFileHeader->bfOffBits;

    if (m_hDrawDib == NULL || mDispMethod == 0) {
        // 傳統 GDI 繪製邏輯...
    } else {
        // 邊界檢查 mPos...
        DrawDibRealize(m_hDrawDib, dc.GetSafeHdc(), TRUE);

        if (mFullViewTog == 0) { // 1:1 顯示
            CPoint Wid(mDispR.Width(), mDispR.Height());
            Wid.x = min(Wid.x, mpBitmapInfo->biWidth);
            Wid.y = min(Wid.y, mpBitmapInfo->biHeight);
            DrawDibDraw(m_hDrawDib, dc.GetSafeHdc(),
                0, 0, Wid.x, Wid.y,
                mpBitmapInfo, (LPVOID)(mpBitsSrc + bfoffBits),
                mPos.x, mPos.y, Wid.x, Wid.y, DDF_BACKGROUNDPAL);
        } else { // 全屏縮放
            DrawDibDraw(m_hDrawDib, dc.GetSafeHdc(),
                0, 0, mDispR.Width(), mDispR.Height(),
                mpBitmapInfo, (LPVOID)(mpBitsSrc + bfoffBits),
                0, 0, mpBitmapInfo->biWidth, mpBitmapInfo->biHeight, DDF_BACKGROUNDPAL);
        }
    }
}

四、CVIEwBitmap 類完整功能與使用指南

類成員設計

  • HDRAWDIB m_hDrawDib:視頻繪製句柄。
  • HANDLE mhBitsSrc / LPSTR mpBitsSrc:文件內存句柄與指針。
  • BITMAPINFOHEADER* mpBitmapInfo:信息頭指針。
  • CRect mDispR, CPoint mPos:控制顯示區域與滾動偏移。
  • BOOL mFullViewTog, mDispMethod:全屏/1:1 切換、繪製方式切換。

專案集成步驟

  1. 創建 MFC SDI 專案,添加 Bitmap0.h/cpp。
  2. 資源視圖中為主選單「檢視」添加「ViewBitmap」項目 (ID_VIEW_BITMAP)。
  3. CMainFrame::OnViewBitmap 中實例化並顯示視圖:
    pViewBitmap = new CVIEwBitmap("BITMAP.BMP", this); pViewBitmap->ShowWindow(TRUE);
  4. 編譯運行,準備一張大尺寸真彩色 BMP 測試。

進階功能亮點

  • 智能滾動條:圖大於客戶區自動啟用,否則隱藏。
  • 狀態欄資訊:實時顯示圖像屬性、繪製模式、縮放比例,支持點擊切換。
  • 拖放支持:直接從資源管理器拖入 BMP 文件即時顯示。
  • 對比驗證:在全屏縮小、256 色模式下對比 GDI 與 DrawDib,差異一目了然。

結語

通過 DrawDib 替代傳統 GDI 繪製,我們以極低的代碼修改成本,獲得了卓越的性能與視覺質量。這不僅解決了 BMP 顯示的歷史難題,也為 MFC 應用中的圖像處理提供了專業級解決方案。讀者可進一步優化縮放比例保持邏輯,或擴展支持更多圖片格式。

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