2010-10-15 30 views
7

在Win32下的單色位掩碼,它是一種常見的技術做以生成位圖單色位掩碼透明度使用下列內容:如何genrate爲32位的位圖

SetBkColor(hdcSource, clrTransparency); 
VERIFY(BitBlt(hdcMask, 0, 0, bm.bmWidth, bm.bmHeight, hdcSource, 0, 0, SRCCOPY)); 

這假定hdcSource是一個保存源圖像的存儲器DC,hdcMask是保存相同大小的單色位圖的存儲器DC(因此它們都是32x32,但是源是4位顏色,而目標是1位單色)。

但是,當源是32位顏色+ alpha時,這似乎失敗了。而不是在hdcMask中獲取單色位圖,我得到一個全黑的蒙版。沒有位被設置爲白色(1)。而這適用於4位色彩源。

我的search-foo失敗了,因爲我似乎無法找到對此特定問題的任何引用。

我已經隔離,這確實是我的代碼中的問題:即如果我使用16色(4位)的源位圖,它的工作原理;如果我使用32位圖像,則會生成全黑色蒙版。

在32位彩色圖像的情況下,我應該使用另一種方法嗎? alpha通道是否會覆蓋上述技術的正常行爲?

感謝您提供的任何幫助!

附錄:我仍然無法找到爲我的GDI +生成的源位圖創建有效單色位圖的技術。

通過簡單地根本不生成單色位掩碼,我已經略微緩解了我的特定問題,而是使用了TransparentBlt(),這似乎是正確的(但我不知道他們在內部做了什麼這是允許他們正確掩蓋圖像的任何不同)。

這可能是有用的,有一個非常好的,工作職能:

HBITMAP CreateTransparencyMask(HDC hdc, HBITMAP hSource, COLORREF crTransparency); 

凡總是創建一個有效的透明面罩,無論hSource的顏色深度。

想法?

+3

GDI停留在24bpp。 TransparentBlt()有點不尋常,它被記錄爲支持32bpp。也許是轉向GDI +的時候了。 – 2010-10-15 15:31:29

回答

3

如果有alpha通道,則不能這樣做。 COLORREF使用前8位用於許多目的,包括指定是否更低的3個字節是當前調色板中的顏色表索引或RGB三元組。因此,您不能在clrTransparency的高位字節中指定除0x00之外的任何內容。

如果你有一個alpha位圖,那麼對於仍然「不知道」alpha通道的GDI,沒有一種比較24 bit BkColor和位圖中的32位像素的方法。

我希望GDI將32bpp位圖中的alpha通道視爲「保留」,並且只能成功比較保留通道爲零的像素。即無論如何,您的面具顏色必須完全透明纔能有成功的機會。 (並且,如果您製作了合法的預乘位圖,則暗示RGV值也將爲零,而非限制您選擇的掩模顏色:P)

+0

在這種特殊情況下,問題是我從4位彩色位圖開始。然後,爲了在禁用時以很好的方式顯示它,我想對它進行灰度級渲染,然後將其用作按鈕面(使用之前的遮罩透明度技術)。但是我用來生成灰階的代碼是基於GDI +的,我懷疑它創建的是32位彩色圖像,而不是24位彩色圖像。 – Mordachai 2010-10-15 14:06:33

+1

@Mordachai:鑑於剛剛描述的內容,您是否可以從原始的4位圖像製作遮罩並將其用於GDI創建的遮罩? – 2010-10-15 15:46:11

+0

我喜歡這個主意。但是我仍然對一個通用的「如何爲* ANY *源HBITMAP創建一個單色位掩碼」感興趣。 – Mordachai 2010-10-15 18:11:08

0

另一種方法是自己掃描像素並生成單色位圖基於源顏色(或源阿爾法與閾值)。

請注意,如果您使用的是GDI +,則根據操作情況,像素可能已經過抗鋸齒處理,導致它們中的任何一個都不會與您的「透明」顏色匹配。

+0

我將GDI +生成的灰度圖像保存爲32位深度PNG,然後對Paint中的像素進行採樣。他們沒事。但是,我仔細檢查了GDI +產生的最終HBITMAP(通過Bitmap :: GetHBitmap()),它確實總是32位深度,儘管底層Bitmap實例是PixelFormat24bppRGB)。 – Mordachai 2010-10-15 16:07:45

3

可以做:)
正如上面的'克里斯貝克'指出的那樣,GDI只有在保留的Alpha通道爲零時才能比較。
從BITMAP :: GetHBITMAP()獲取的HBITMAP返回一個HBITMAP,其Alpha通道全部設置爲0xFF。
SetBkColor()比較結果必須爲0x00。
因此,Soln:遍歷每個像素並將Alpha組件設置爲零。

Bitmap img(L"X.bmp"); 
HBITMAP hBM; 
img.GetHBITMAP(Color::White, &hBM); 
BITMAP bm; 
GetObject(g_hbmBall, sizeof(BITMAP), &bm); 
for(UINT i = 0, n = -1; i < bm.bmHeight; i++) 
    for(UINT j = 0; j < bm.bmWidth; j++) 
    { 
     n += 4; // Once per Pixel of 4 Bytes 
     ((LPBYTE)bm.bmBits)[n] = 0; 
    }
// Now SetBkColor and BitBlt will work as expected
+0

感謝您的想法。我最終決定不使用這種技術,所以這個編碼分支目前已經失效。我可能會在未來回到它,然後再嘗試這個想法。 ;) – Mordachai 2011-01-03 18:28:21

0

我工作的方法是先將位圖從32位轉換爲24位。

1. CreateCompatibleDC 
2. CreateDIBSection with 24 as the biBitCount. 
3. SelectObject 
4. BitBlt from 32bit DC to 24 bit. This removes alpha. 
5. BitBlt from 24 bit DC to the monochrome DC works as expected. 

在我的機器上,這比Ujjwal的答案執行得更快。

+0

謝謝。很高興知道。 – Mordachai 2012-12-10 19:54:42

+0

只是爲了使這個方法更清晰,a。 3)SelectObject將選擇使用CreateDIBSection創建的位圖到1)b中創建的新DC中。爲了創建遮罩,您需要確保在1)中創建的新的24位DC上調用SetBkColor,我偶爾在32位DC上調用了SetBkColor,並且需要一段時間才能排除故障。 – frank 2016-02-14 01:09:52