从字节数组生成Bitmap无显示:我的代码问题出在哪里?
字节数组生成Bitmap无法在图片控件显示的问题排查
我尝试从字节数组生成Bitmap并设置到图片控件PICTURE_MY上,但图片无法显示。以下是我的代码实现,请帮忙排查问题:
OnInitDialog 代码
PICTURE_MY.GetWindowRect(&rect); //PICTURE_MY 是我的图片控件 MAX_CANVAS_W = rect.right - rect.left; MAX_CANVAS_H = rect.bottom - rect.top; layerOne = new BYTE[3*((MAX_CANVAS_W-2)*(MAX_CANVAS_H-2))]; pitch = MAX_CANVAS_W - 2; int count = 0; while (count < 3 * ((MAX_CANVAS_W - 2) * (MAX_CANVAS_H - 2))) { layerOne[count] = 255; count++; }
OnPaint 代码
HBITMAP h_bitmap = CreateBitmap(pitch, MAX_CANVAS_H - 2, 1, 24, layerOne); CImage image; image.Attach(h_bitmap); PICTURE_MY.SetBitmap(image);
另外,我用以下代码可以正常显示,但效率太低,不想采用:
CClientDC dc(this); for (int y = 0; y < MAX_CANVAS_H - 2; y++) { for (int x = 0; x < pitch; x++) { COLORREF color = RGB(layerOne[3*(y*pitch+x)], layerOne[3 * (y * pitch + x)+1], layerOne[3 * (y * pitch + x)+2]); dc.SetPixel(PICTURE_LEFTTOP.x+1 + x, PICTURE_LEFTTOP.y+y+1, color); } }
问题原因及解决方法
- DIB对齐与格式兼容问题
CreateBitmap生成的是依赖设备的位图(DDB),24位DDB要求每行像素数据按4字节对齐。如果你的pitch(即每行像素数)不是4的倍数,数据排布不符合要求,会导致位图解析失败。
解决方法:改用CreateDIBSection创建设备无关位图(DIB),它支持自定义行间距,无需强制4字节对齐,且兼容性更好:
// 替换OnPaint中的原代码 BITMAPINFO bmi = {0}; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = pitch; bmi.bmiHeader.biHeight = -(MAX_CANVAS_H - 2); // 负数值表示像素数组按顶行在前的顺序存储 bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = 24; bmi.bmiHeader.biCompression = BI_RGB; bmi.bmiHeader.biSizeImage = 3 * pitch * (MAX_CANVAS_H - 2); HBITMAP h_bitmap = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, NULL, NULL, 0); if (h_bitmap) { // 将layerOne的数据拷贝到位图内存中 BITMAP bmp; GetObject(h_bitmap, sizeof(bmp), &bmp); BYTE* pBits = (BYTE*)bmp.bmBits; memcpy(pBits, layerOne, 3 * pitch * (MAX_CANVAS_H - 2)); PICTURE_MY.SetBitmap(h_bitmap); DeleteObject(h_bitmap); // SetBitmap会接管位图句柄,此处可释放 }
- 像素顺序不匹配
Windows 24位位图默认采用BGR(蓝、绿、红)的像素顺序,但你的低效代码中用RGB(红,绿,蓝)转换,说明layerOne数组是RGB顺序。如果直接用原数组生成位图,颜色会出现异常(全白场景可能看不出,但其他颜色会出错)。
如果要保留RGB顺序的数组,可修改BITMAPINFO的颜色掩码:
bmi.bmiHeader.biBitCount = 24; bmi.bmiHeader.biCompression = BI_BITFIELDS; // 定义RGB对应的掩码,匹配数组的颜色顺序 DWORD dwMask[] = {0x00FF0000, 0x0000FF00, 0x000000FF}; memcpy(&bmi.bmiColors, dwMask, sizeof(dwMask));
- CImage中转冗余
原代码里通过CImage中转位图句柄完全没必要,SetBitmap直接接收HBITMAP即可,去掉中转能减少资源管理风险。
内容的提问来源于stack exchange,提问作者이지선
相关产品推荐
相关产品推荐

