2015-04-02 88 views
0

我一直試圖從文件中加載16位(A1R5G5B5)BMP,並將其Alpha通道用作位掩碼。除了過去一週一直困擾着我的一個問題之外,我已經做好了一切工作。這是因爲,當我使用CreateDIBitmap來創建帶有字節緩衝區的1位通道時,創建的位圖僅在第一次繪製時使用所有位的反轉。在下一次繪畫時,這些比特正確地翻轉所提供的數據,並保持這樣的狀態以用於之後的所有繪製。這種行爲非常奇怪,並且發生在所有Windows版本上,我已經將其跟蹤到與HDC的某種設置以及可能的CreateDIBitmap設置有關。我已經嘗試了很多事情,包括將HDC的前景和背景顏色設置爲前後許多值,但我嘗試過的所有內容仍然保持這種行爲。GDI單色位圖在每次創建HBITMAP時翻轉位

這裏是一個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可能會使用不同的調色板,而不是第一個導致此行爲的調色板。

回答

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 
); 
}