BMP位圖之代碼實現

從16位開始,不存在調色板,頂多存在一個RGBQUAD的掩碼。windows

16位位圖,我沒有拿到對應的素材,可是根據官方文檔的描述和代碼驗證後,我總結爲下:api

當biCompression爲BI_RGB時,此時是RGB555格式,不存在調色板。app

當biCompression爲BI_BITFIELDS時,16位位圖時RGB565格式,對應的32位是帶掩碼的格式,兩種都有一個RGBQUAD的數據存在於調色板。工具

24位位圖,只有BI_RGB存儲方式。測試

代碼實現以下spa

enum { bitmap_undefined, bitmap_unknown, bitmap1, bitmap4, bitmap4_RLE4,
    bitmap8, bitmap8_RLE8, bitmap16_RGB555, bitmap16_RGB565, bitmap24, bitmap32, bitmap32_mask};//全部bmp類型


class Bitmap {
public:
    Bitmap();
    virtual ~Bitmap();
    HBITMAP BitCreate(HDC hDC, LPTSTR szFilename);//從文件載入
    HBITMAP BitCreate(HDC hDC, HINSTANCE hInstance, UINT rscID);//從資源載入
    PBITMAPFILEHEADER GetBitFileheader(PBYTE pBitmap = NULL);//位圖頭
    PBITMAPINFOHEADER GetBitInfoheader(PBYTE pBitmap = NULL);//位圖INFO結構
    LPRGBQUAD GetBitPalette(PBYTE pBitmap = NULL);//位圖畫板,不存在返回NULL
    PVOID GetBitData(PBYTE pBitmap = NULL);//位圖數據
    void BitDraw(HDC hDC, int x, int y, HBITMAP hBitmap);//將位圖畫到本身的窗口
protected:
    void BitErrorshow(DWORD errorID);//錯誤提示
    void BitTypedefined();//類型定義
    void BitFree();//資源釋放
    HBITMAP BitLoad(HDC hDC, PBYTE pBitmap = NULL);//載入的數據,轉換爲HBITMAP句柄,方便操做
private:
    HGLOBAL m_hGlablebitmap;
    HANDLE m_hFilemapping;
    PBYTE m_pBitmap;
    int m_iWidth, m_iHeight, m_iFilesize;
    int m_iType;
};

對應的實現代碼code

Bitmap::Bitmap() {
    m_hFilemapping = m_hGlablebitmap = NULL;
    m_pBitmap = NULL;
    m_iFilesize = m_iWidth = m_iHeight = 0;
    m_iType = bitmap_undefined;
}

Bitmap::~Bitmap() {
    BitFree();
}

void Bitmap::BitTypedefined() {
    PBITMAPINFOHEADER bInfoheader;
    bInfoheader = GetBitInfoheader();
    m_iWidth = bInfoheader->biWidth;
    m_iHeight = bInfoheader->biHeight;
    WORD bitCount = bInfoheader->biBitCount;
    DWORD bitCompression = bInfoheader->biCompression;
    if (bitCompression == BI_RGB) {
        switch (bitCount) {
        case 1:
            m_iType = bitmap1; break;
        case 4:
            m_iType = bitmap4; break;
        case 8:
            m_iType = bitmap8; break;
        case 16:
            m_iType = bitmap16_RGB555; break;
        case 24:
            m_iType = bitmap24; break;
        case 32:
            m_iType = bitmap32; break;
        default:
            m_iType = bitmap_unknown;
        }
    }
    else if (bitCompression == BI_BITFIELDS) {
        switch (bitCount) {
        case 16:
            m_iType = bitmap16_RGB565; break;
        case 32:
            m_iType = bitmap32_mask; break;
        default:
            m_iType = bitmap_unknown;
        }
    }
    else if (bitCompression == BI_RLE4)
        m_iType = bitmap4_RLE4;
    else if (bitCompression == BI_RLE8)
        m_iType = bitmap8_RLE8;
    else
        m_iType = bitmap_unknown;
}

HBITMAP Bitmap::BitLoad(HDC hDC, PBYTE pBitmap) {
    PBITMAPINFOHEADER pBitmapinfo = GetBitInfoheader(pBitmap);
    PBYTE pBitmapdata = (PBYTE)GetBitData(pBitmap), pDIBData = NULL;
    HBITMAP hBitmap = CreateDIBSection(hDC, (PBITMAPINFO)pBitmapinfo, DIB_RGB_COLORS, (void **)&pDIBData,
        NULL, 0);
    DWORD sizeImage = m_iFilesize - (DWORD)(pBitmapdata - pBitmap);//永遠本身計算數據大小,由於位圖INFO頭中的biSizeImage字段可能爲0.
    CopyMemory(pDIBData, pBitmapdata, sizeImage);
    return hBitmap;
}

void Bitmap::BitErrorshow(DWORD errorID) {
    TCHAR szCaption[64];
    LPVOID lpMsgBuf;
    wsprintf(szCaption, L"錯誤代碼:0x%08x", errorID);
    FormatMessage(
        FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
        NULL,
        errorID,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPTSTR)&lpMsgBuf,
        0, NULL);
    MessageBox(NULL, (LPTSTR)lpMsgBuf, szCaption, MB_OK | MB_ICONSTOP);
    LocalFree(lpMsgBuf);
}

HBITMAP Bitmap::BitCreate(HDC hDC, LPTSTR szFilename) {
    HANDLE hFile = NULL;
    BitFree();//釋放以前數據
    __try {
        hFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL,
            OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        m_hFilemapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
        m_pBitmap = (PBYTE)MapViewOfFile(m_hFilemapping, FILE_MAP_READ, 0, 0, 0);
        m_iFilesize = GetFileSize(hFile, 0);
        BitTypedefined();
    }__except (EXCEPTION_EXECUTE_HANDLER) {
        BitErrorshow(GetLastError());
        CloseHandle(hFile);
        BitFree();
        return NULL;
    }
    CloseHandle(hFile);
    return BitLoad(hDC, m_pBitmap);
}

HBITMAP Bitmap::BitCreate(HDC hDC, HINSTANCE hInstance, UINT rscID) {
    HRSRC hResInfo = NULL;
    BitFree();//釋放以前數據
    __try {
        hResInfo = FindResource(hInstance, MAKEINTRESOURCE(rscID), RT_BITMAP);
        m_hGlablebitmap = LoadResource(hInstance, hResInfo);
        m_pBitmap = (PBYTE)LockResource(m_hGlablebitmap);
        m_iFilesize = SizeofResource(hInstance, hResInfo);
        BitTypedefined();
    }__except (EXCEPTION_EXECUTE_HANDLER) {
        BitErrorshow(GetLastError());
        BitFree();
        return NULL;
    }
    return BitLoad(hDC, m_pBitmap);
}

void Bitmap::BitFree() {
    if (m_hFilemapping != NULL) {
        UnmapViewOfFile(m_pBitmap);
        CloseHandle(m_hFilemapping);
        m_hFilemapping = NULL;
    }
    else if (m_hGlablebitmap != NULL) {
        UnlockResource(m_hGlablebitmap);
        FreeResource(m_hGlablebitmap);
        m_hGlablebitmap = NULL;
    }
    m_pBitmap = NULL;
    m_iType = bitmap_undefined;
    m_iFilesize = m_iHeight = m_iWidth = 0;
}

PBITMAPFILEHEADER Bitmap::GetBitFileheader(PBYTE pBitmap) {
    if (m_hFilemapping != NULL)
        return pBitmap ? (PBITMAPFILEHEADER)pBitmap : (PBITMAPFILEHEADER)m_pBitmap;
    return NULL;
}

PBITMAPINFOHEADER Bitmap::GetBitInfoheader(PBYTE pBitmap) {
    DWORD offset = 0;
    if (m_hFilemapping != NULL) 
        offset = sizeof(BITMAPFILEHEADER);
    return pBitmap ? (PBITMAPINFOHEADER)(pBitmap + offset) : (PBITMAPINFOHEADER)(m_pBitmap + offset);
}

LPRGBQUAD Bitmap::GetBitPalette(PBYTE pBitmap) {
    PBITMAPINFOHEADER pBitmapinfo = GetBitInfoheader(pBitmap);
    PBYTE pPalette = (PBYTE)pBitmapinfo + sizeof(PBITMAPINFOHEADER), pData = (PBYTE)GetBitData(pBitmap);
    if (pPalette == pData)//不存在調色板
        return NULL;
    return (LPRGBQUAD)pPalette;
}

PVOID Bitmap::GetBitData(PBYTE pBitmap) {
    DWORD offset = 0, n;
    PBITMAPINFOHEADER pBitmapinfo = GetBitInfoheader(pBitmap);
    n = pBitmapinfo->biClrUsed ? pBitmapinfo->biClrUsed : pBitmapinfo->biBitCount;
    switch (m_iType) {
    case bitmap1:
    case bitmap4:
    case bitmap4_RLE4:
    case bitmap8:
    case bitmap8_RLE8:
        offset = (DWORD)pow(2, n); break;
    case bitmap16_RGB565:
    case bitmap32_mask:
        offset = 1; break;
    }
    return (PBYTE)pBitmapinfo + offset * sizeof(RGBQUAD)+sizeof (BITMAPINFOHEADER);
}

void Bitmap::BitDraw(HDC hDC, int x, int y, HBITMAP hBitmap){
    if (hBitmap != NULL) {
        HDC hMemDC = CreateCompatibleDC(hDC);
        HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);//載入位圖
        BitBlt(hDC, x, y, m_iWidth, m_iHeight, hMemDC, 0, 0, SRCCOPY);
        SelectObject(hMemDC, hOldBitmap);//還原位圖
        DeleteDC(hMemDC);
    }
}

代碼測試圖orm

1位位圖:blog

4位位圖圖片

8位位圖

24位位圖

其餘位圖能夠隨意測試,均無問題。圖片是我隨意弄的,哈哈哈,本身用windows自帶的畫圖工具就能夠作出不一樣類型的位圖,這裏就不上傳位圖資源文件了。

相關文章
相關標籤/搜索