从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自带的画图工具就可以做出不同类型的位图,这里就不上传位图资源文件了。