GDI单色位图在每次创建HBITMAP时翻转位

时间:2015-04-02 11:08:02

标签: c winapi bitmap gdi alpha

我一直在尝试从文件加载16位(A1R5G5B5)BMP并使用其alpha通道作为位掩码。除了过去一周困扰我的一个问题之外,我已经把一切都搞好了。当我使用CreateDIBitmap制作带有字节缓冲区的1bit通道时,创建的Bitmap仅在第一次绘制时使用其所有位的反转。在下一个画面上,这些位正确地翻转到所提供的数据,然后保持这种方式。这种行为非常奇怪,并且发生在所有Windows版本上,我已将其跟踪到与某些HDC设置和可能的CreateDIBitmap有关。我尝试了很多东西,包括将HDC前后的前景和背景颜色设置为很多值,但是我尝试的所有内容仍然保持这种行为。

这是一个尝试的POC:

BITMAPINFOHEADER bmih;
BITMAPINFO bmi;
HBITMAP mask;
PBYTE data;
PBYTE alpha;
SIZE dimension;
void WhenCreated() // WM_CREATE
{
    dimension.cx=3;
    dimension.cy=1;
    alpha=(PBYTE)malloc(1);
    data=(PBYTE)malloc(1);
    alpha[0]=0xA0; // 0b10100000
}
#define BIN_SCAPE(B,A) (B[0]&(1<<A))?1:0
void WhenPresenting(HDC H) // WM_PAINT
{
   printf(
       "ALPHA:\t%i %i %i\n",
       BIN_SCAPE(alpha,7),
       BIN_SCAPE(alpha,6),
       BIN_SCAPE(alpha,5)
    );
    HDC memory;
    HBITMAP matter;
    memory=CreateCompatibleDC(NULL);
    memset(&bmi,0x0,sizeof(BITMAPINFO));
    bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
    bmi.bmiHeader.biWidth=dimension.cx;
    bmi.bmiHeader.biHeight=dimension.cy;
    bmi.bmiHeader.biPlanes=1;
    bmi.bmiHeader.biBitCount=1;
    bmi.bmiHeader.biCompression=BI_RGB;
    memset(&bmih,0x0,sizeof(BITMAPINFOHEADER));
    bmih.biSize=sizeof(BITMAPINFOHEADER);
    bmih.biWidth=bmi.bmiHeader.biWidth;
    bmih.biHeight=bmi.bmiHeader.biHeight;
    mask=CreateDIBitmap(
        memory,
        &bmih,
        CBM_INIT,
        alpha,
        &bmi,
        DIB_RGB_COLORS
    );
    SelectObject(memory,mask);
    GetDIBits(memory,mask,0,1,data,&bmi,DIB_RGB_COLORS);
    printf(
       "DATA:\t%i %i %i\n",
       BIN_SCAPE(data,7),
       BIN_SCAPE(data,6),
       BIN_SCAPE(data,5)
     );
     StretchBlt(
         H,
         0,0,128,128,
         memory,
         0,0,dimension.cx,dimension.cy,
         SRCCOPY
     );
     DeleteDC(memory);
     DeleteObject(mask);
}

当程序加载时,显示的数据与给定的数据相反,后续绘画使得数据适合控制台输出中提供的数据,肯定会发生翻转。我的猜测是第一个提供的HDC可能会使用不同的调色板而不是第一个导致此行为的调色板?

1 个答案:

答案 0 :(得分:0)

现在一切都有意义,它正在改变。

  

“biBitCount成员小于16,biClrUsed成员指定图形引擎或设备驱动程序访问的实际颜色数。” (来自msdn)

如果你在CreateDIBitmap中使用彩色HDC,你会得到一个黑色的颜色,这个颜色会在每次重绘时发生变化,这会引起你的反响,直到你明白是因为你还没有设置调色板。 HBITMAP因为在制作每个HDC时它的调色板是未定义的,除非指定。您可以使用SetDIBits,但如果您想在CreateDIBitmap期间完成它,请尝试以下方法:

PBITMAPINFO pbmi;
RGBQUAD palette[2];
{
// this will give you white (1) and black (0)
palette[0].rgbBlue=0x00;
palette[0].rgbGreen=0x00;
palette[0].rgbRed=0x00;
palette[1].rgbBlue=0xFF;
palette[1].rgbGreen=0xFF;
palette[1].rgbRed=0xFF;
// using a PBITMAPINFO in order to allocate room for palette
pbmi=(PBITMAPINFO)LocalAlloc(LPTR,sizeof(BITMAPINFO)+sizeof(RGBQUAD)*2); // this technically allocates an extra RGBQUAD
pbmi->bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth=dimension.cx;
pbmi->bmiHeader.biHeight=dimension.cy;
pbmi->bmiHeader.biPlanes=1;
pbmi->bmiHeader.biBitCount=1;
pbmi->bmiHeader.biCompression=BI_RGB;
pbmi->bmiHeader.biClrUsed=2; // palette is two colors long
pbmi->bmiHeader.biClrImportant=2;
memcpy(pbmi->bmiColors,palette,sizeof(RGBQUAD)*2);
mask=CreateDIBitmap(
    memory,
    &bmih,
    CBM_INIT,
    alpha,
    pbmi,
    DIB_RGB_COLORS
);
}