C++使用24位RGB格式创建DDB灰度位图底部出现黑色块问题求助
问题原因
- 核心原因是
CreateCompatibleBitmap创建的位图位深度与你构造的24位RGB数据不匹配:该API会继承传入DC的位深度,当前主流系统显示位深度为32位,你按24位长度传入像素数据,总数据量不足32位位图的要求,导致底部区域像素没有被赋值,出现黑块。 - 隐含问题:你在
WM_PAINT中反复创建HBITMAP对象,未释放前一次创建的对象,会造成GDI资源泄漏,运行时间过长会导致界面绘制异常。 - 通用隐患:GDI位图要求每行像素数据长度必须为4字节的整数倍,你当前1024宽度刚好满足
1024*3=3072是4的倍数,若更换其他宽度也会出现绘制异常。
解决方案
推荐使用CreateDIBSection创建指定格式的DIB位图,完全可控像素数据格式,不会出现位深度不匹配的问题,修改后的关键代码如下:
1. 变量定义修改
// WndProc内的静态变量修改为: static HBITMAP hBitmap = NULL; static BYTE* lpBits = NULL;
2. WM_CREATE逻辑修改
case WM_CREATE: { // 定义24位RGB位图信息头 BITMAPINFO bmi = {0}; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = 1024; // 高度设为负数表示位图是顶行向下的布局,和你填充数据的顺序一致,无需坐标翻转 bmi.bmiHeader.biHeight = -408; bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 24; bmi.bmiHeader.biCompression = BI_RGB; HDC hdc = GetDC(hWnd); // 创建DIB位图,直接获取像素缓冲区指针 hBitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**)&lpBits, NULL, 0); ReleaseDC(hWnd, hdc); int grayVal = 0; // 计算行步长,保证4字节对齐 int rowStride = (1024 * 3 + 3) / 4 * 4; for (int y = 0; y < 408; y++) { BYTE* pRow = lpBits + y * rowStride; for (int x = 0; x < 1024; x++) { // 24位位图存储顺序为B、G、R pRow[x * 3 + 0] = grayVal; pRow[x * 3 + 1] = grayVal; pRow[x * 3 + 2] = grayVal; } grayVal++; if (grayVal > 255) grayVal = 0; } break; }
3. WM_PAINT逻辑修改
case WM_PAINT: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hWnd, &ps); RECT clientRect; GetClientRect(hWnd, &clientRect); HDC hdcMem = CreateCompatibleDC(hdc); HBITMAP hOldBmp = (HBITMAP)SelectObject(hdcMem, hBitmap); StretchBlt(hdc, clientRect.left, clientRect.top, clientRect.right, clientRect.bottom, hdcMem, 0, 0, 1024, 408, SRCCOPY); // 选回原有位图,避免资源泄漏 SelectObject(hdcMem, hOldBmp); DeleteDC(hdcMem); EndPaint(hWnd, &ps); break; }
4. 资源释放逻辑保持即可
WM_DESTROY中调用DeleteObject(hBitmap)即可,CreateDIBSection分配的像素缓冲区会随位图对象一起释放,无需手动释放。
内容的提问来源于stack exchange,提问作者Brian Bai
相关产品推荐
相关产品推荐

