将位图绘制为一维字节数组,而不是RGBQUAD对象。GDI StretchDIBits

后端开发 2026-07-11

我有一个 int 数组,其中每4个元素描述图像中每个像素的蓝、绿、红和alpha值,例如:

int data[] = {255,0,0,255, 0,255,0,255, 0,0,255,255}

表示一个3×1像素的图像,像素按顺序为蓝色、绿色和红色且不透明。

我想用GDI将它绘制到窗口上。看起来最合适的函数是 SetDIBitsToDevice,但似乎它不支持混合,因此alpha通道将被忽略。

然后,我尝试使用 StretchDIBits

我尝试绘制一个简单的实色矩形,例如绿色,但它总是绘制成蓝色矩形,更准确地说,是蓝色竖条,这取决于我指定的分量数量:

  BITMAPINFO bmi;
    ZeroMemory(&bmi, sizeof(BITMAPINFO));
    bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
    bmi.bmiHeader.biBitCount = 32;
    bmi.bmiHeader.biHeight = h;
    bmi.bmiHeader.biWidth = w;
    bmi.bmiHeader.biPlanes = 1;
    bmi.bmiHeader.biCompression = BI_RGB;

    int *data2 = new int[w*h *4];
     for(int i = 0; i < w*h; i++)
    {
        data2[i*4] = 0;
        data2[i*4+1] = 255;
        data2[i*4+2] = 0;
        data2[i*4+3] = 255;       
    }
    SetDIBitsToDevice(hdc, 0, 0, w, h, 0, 0, 0, h, data2, &bmi, DIB_RGB_COLORS);
    delete[] data2; // same behaviour for SetDIBitsToDevice

输出结果(如果你仔细看,显然不是实心的):

enter image description here

如果也设置 data2[i*4+1] = 0,那么蓝色条纹会更少一些:

enter image description here

看起来似乎它期望数组元素不是像素分量,而是某种“整个位像素”的数据。某处我看到其实指定的是一个 RGBQUAD 对象数组,而不是 int,但我对 intchar 这样的数组更感兴趣,其中的元素是像素分量,如文章开头所示。

我尝试把 bmiHeader.biCompression = BI_BITFIELDS 应用于 BITMAPINFO,但如果之前显示有错,现在就完全不绘制任何内容。

如果把数组长度设得比应有的还长,一些随机像素会在底部出现。也许数组实际上还应包含头部,这样像素数据就会有偏移?

问题:我能直接把字节数组传给 StretchDIBits,而不是对象吗?如果可以,那么到底应该如何实现?

解决方案

由于某些原因,MSDN对 BITMAPV4HEADER 中biBitCount值的描述更为丰富,而它似乎与仅 BITMAPINFOHEADER 的行为相同。

32 - 位图数组中的每个DWORD表示一个像素的蓝、绿、红三种分量的相对强度。蓝色分量位于最低有效的8 位,其次是绿色和红色各占用8 位。每个DWORD的高字节不使用。

然而,正如Remy Lebeau提到的,数据可以以数组形式传递,其中每个元素是对应像素的通道(因此像素由四个数组元素描述),也可以是每个数组元素就是整个像素:

这是因为WinAPI无论如何都会逐字节读取提供的缓冲区,并且期望每四个字节都对应相应像素的相应通道。

因此缓冲区可以是 unsigned char,此时每个元素都是单独的通道,因为 sizeof(char)1,或者 DWORD,在大多数情况下是 int,因为 sizeof(int)(在大多数情况下)是 4,然后每个数组元素需要进行位级编辑来指定像素,即前8 位应包含蓝色(一个字节)的值,接下来的8 位直到第16位应包含绿色,依此类推,直到第32位。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章