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

C GDI单色位图在每次创建HBITMAP时翻转位,c,winapi,bitmap,gdi,alpha,C,Winapi,Bitmap,Gdi,Alpha,我一直在尝试从文件中加载16位A1R5G5B5 BMP,并将其alpha通道用作位掩码。除了一个在过去一周一直困扰着我的问题外,我一切都很好。这是因为,当我使用CreateDIBitmap创建带有字节缓冲区的1bit通道时,创建的位图仅在第一次绘制时使用其所有位的倒数。在下一次绘制时,位正确地翻转到提供的数据,并在绘制之后的所有绘制中保持这种方式。这种行为非常奇怪,在所有Windows版本上都会发生,我一直追踪到它与HDC的某种设置以及可能的CreateDIBitmap有关。我尝试了很多方法,包

我一直在尝试从文件中加载16位A1R5G5B5 BMP,并将其alpha通道用作位掩码。除了一个在过去一周一直困扰着我的问题外,我一切都很好。这是因为,当我使用CreateDIBitmap创建带有字节缓冲区的1bit通道时,创建的位图仅在第一次绘制时使用其所有位的倒数。在下一次绘制时,位正确地翻转到提供的数据,并在绘制之后的所有绘制中保持这种方式。这种行为非常奇怪,在所有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可能会使用与第一个HDC之后的所有HDC不同的调色板,这导致了这种行为?

现在一切都有意义了,是调色板在改变

BIBITCUNT成员小于16,BICLRUSE成员指定图形引擎或设备驱动程序访问的实际颜色数。来自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
);
}