BMP位图之代码实现

从16位开始,不存在调色板,顶多存在一个RGBQUAD的掩码。

16位位图,我没有拿到对应的素材,但是根据官方文档的描述和代码验证后,我总结为下:

当biCompression为BI_RGB时,此时是RGB555格式,不存在调色板。

当biCompression为BI_BITFIELDS时,16位位图时RGB565格式,对应的32位是带掩码的格式,两种都有一个RGBQUAD的数据存在于调色板。

24位位图,只有BI_RGB存储方式。

代码实现如下

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;
};

对应的实现代码

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);
    }
}

代码测试图

1位位图:

4位位图

8位位图

24位位图

其他位图可以随意测试,均无问题。图片是我随意弄的,哈哈哈,自己用windows自带的画图工具就可以做出不同类型的位图,这里就不上传位图资源文件了。

原文地址:https://www.cnblogs.com/dalgleish/p/9575651.html