2010-10-15 21 views
7

Pod Win32, jest powszechną techniką w celu wygenerowania bitową monochromatyczny z bitmapy do celów przejrzystości, wykonując następujące czynności:Jak genrate maskę monochromatyczny bitową bitmapę 32bit

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

ta zakłada, że ​​hdcSource jest pamięć DC trzymającą obraz źródłowy, a hdcMask jest pamięcią DC z pamięcią trzymającą monochromatyczną bitmapę o tym samym rozmiarze (więc oba mają rozmiar 32x32, ale źródło ma kolor 4-bitowy, natomiast cel jest monochromatyczny 1-bitowy).

Jednak wydaje mi się, że to nie działa, gdy źródło ma kolor 32-bitowy i alfa. Zamiast uzyskać monochromatyczną bitmapę w hdcMask, dostaję maskę, która jest cała czarna. Żadne bity nie są ustawione na biały (1). Podczas gdy działa to dla źródła koloru 4bit.

Moje wyszukiwanie-foo zawodzi, ponieważ nie mogę znaleźć żadnych odniesień do tego konkretnego problemu.

Wyizolowałem, że jest to rzeczywiście problem w moim kodzie: tzn. Jeśli używam mapy bitowej źródła, która ma 16 kolorów (4bit), działa; jeśli użyję obrazu 32-bitowego, generuje on całkowicie czarną maskę.

Czy istnieje alternatywna metoda, której powinienem używać w przypadku 32-bitowych kolorowych obrazów? Czy istnieje problem z kanałem alfa, który przesłania normalne zachowanie powyższej techniki?

Dziękujemy za każdą pomoc, którą możesz zaoferować!

ADDENDUM: Nadal nie mogę znaleźć techniki, która tworzy poprawną monochromatyczną mapę bitową dla mojej mapy bitowej źródła generowanej przez GDI +.

W pewien sposób złagodziłem mój konkretny problem, po prostu nie generując monochromatycznej maski bitowej, a zamiast tego używam TransparentBlt(), która wydaje się dobrze to robić (ale nie wiem, co robią wewnętrznie to wszystko, co pozwala im prawidłowo zamaskować obraz).

To może być przydatne, aby mieć naprawdę dobry, funkcję roboczą:

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

gdzie zawsze tworzy prawidłową maskę przezroczystości, niezależnie od głębokości koloru hSource.

Pomysły?

+3

GDI utknął na 24bpp. TransparentBlt() jest nieco nietypowy, udokumentowany jest do obsługi 32bpp. Czas na przejście do GDI + być może. –

Odpowiedz

3

Nie można tego zrobić, jeśli istnieje kanał alfa. COLORREF używa 8 najwyższych bitów do różnych celów, w tym do określenia najmniejszych 3 bajtów, czyli indeksu tabeli kolorów do bieżącej palety lub tripletu RGB. W związku z tym nie można podać niczego oprócz 0x00 w górnym bajcie clrTransparency.

Jeśli masz bitmapę alfa, do GDI, która pozostaje "nieświadoma" kanału alfa, nie ma rozsądnego sposobu na porównanie 24-bitowego BkColor z 32-bitowymi pikselami w bitmapie.

Oczekuję, że GDI potraktuje kanał alfa w mapach bitowych 32 pb jako "Zarezerwowane" i tylko z powodzeniem porówna piksele, w których zarezerwowany kanał wynosi zero. to znaczy, że twój kolor maski musi być w pełni przezroczysty, aby mieć szansę na sukces. (a jeśli wziąłeś się uzasadniony premultiplied bitmapę, która implikuje wartości RGV byłby zerowy też raczej ograniczać wybór kolorów maski: P)

+0

W tym konkretnym przypadku problem polega na tym, że zaczynam od 4-bitowej bitmapy kolorów. Następnie, aby wyświetlić go w przyjemny sposób, gdy jest wyłączony, chciałbym zrobić jego rendering w skali szarości, a następnie użyć go jako przycisku (używając techniki maskowania przezroczystości, jak poprzednio). Ale kod, którego używam do tworzenia skali szarości, bazuje na GDI +, co, jak podejrzewam, tworzy obraz 32-bitowy zamiast 24-bitowego. – Mordachai

+1

@Mordachai: Biorąc pod uwagę to, co właśnie opisałeś, możesz utworzyć maskę z oryginalnego obrazu 4-bitowego i użyć jej z utworzonym przez GDI? –

+0

Podoba mi się pomysł na moje cele. Ale nadal byłbym zainteresowany ogólną "jak stworzyć monochromatyczną maskę bitową dla * KAŻDEGO * źródła HBITMAP". – Mordachai

0

Alternatywną metodą byłoby skanowanie pikseli siebie i generować i monochromatyczne bitmapa na podstawie koloru źródłowego (lub źródła alfa versus próg).

Należy zauważyć, że jeśli używasz GDI +, to w zależności od operacji piksele mogły być ustawione antyaliasingowo, przez co żaden z nich nie jest dopasowany do Twojego "przezroczystego" koloru.

+0

Zapisałem obraz w skali szarości generowany przez GDI + jako 32-bitową głębokość PNG, a następnie próbkowałem piksele w programie Paint. Są w porządku. Jednak dwukrotnie sprawdziłem wynikowy HBITMAP, który generuje GDI + (za pośrednictwem Bitmap :: GetHBitmap()) i rzeczywiście ma on zawsze 32-bitową głębię, pomimo że podstawową instancją Bitmap jest PixelFormat24bppRGB). – Mordachai

3

Może zrobić :)
Jak wskazano powyżej "Chris Becke", GDI można porównać tylko wtedy, gdy zarezerwowany kanał Alfa ma wartość zero.
HBITMAP pobrano z BITMAP :: GetHBITMAP() zwraca HBITMAP z kanałem alfa ustawionym na 0xFF.
To musi być 0x00, aby funkcja SetBkColor() mogła działać.
W związku z tym Soln: Przeprowadź pętlę przez każdy piksel i ustaw składnik alfa na zero.

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

Dzięki za pomysł. W końcu zdecydowałem się nie korzystać z tej techniki, więc ta gałąź kodu jest obecnie nieczynna. Mogę do niego wrócić w przyszłości i wtedy wypróbuję ten pomysł. ;) – Mordachai

0

Metoda, która zadziałała, polegała na konwersji bitmapy z 32 bitowej na 24 bitową.

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. 

Na moim komputerze wykonuje się szybciej niż podwójna pętla z odpowiedzi Ujjwal.

+0

Dzięki. Dobrze wiedzieć. – Mordachai

+0

Tylko po to, aby ta metoda była bardziej przejrzysta, a. 3) SelectObject wybiera mapę bitową utworzoną za pomocą CreateDIBSection na nowy DC utworzony w 1) b. Aby utworzyć maskę, musisz upewnić się, że wywołasz SetBkColor na nowym 24-bitowym DC utworzonym w 1), przypadkowo ustawiłem SetBkColor na 32-bitowym DC, i zajęło to trochę czasu, aby rozwiązać problem. – frank