2010-10-15 8 views
7

Под Win32, это распространенный методом для создания монохромной битовой маски из растрового изображения для использования прозрачности, выполнив следующие действия:Как genrate монохромных битовой маски для 32-битного растрового

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

Это предполагает, что hdcSource является постоянное запоминающее устройство, содержащее исходное изображение, и hdcMask - это постоянный объем памяти, поддерживающий монохромный растровый рисунок того же размера (оба они равны 32x32, но источник имеет 4-битовый цвет, а целевой - 1 бит монохромный).

Однако, похоже, это не срабатывает для меня, когда источником является 32-битный цвет + альфа. Вместо того, чтобы получать монохромное растровое изображение в hdcMask, я получаю маску, которая является черной. Биты не устанавливаются в белый цвет (1). В то время как это работает для 4-битного источника цвета.

Мой поиск-foo не работает, поскольку я не могу найти ссылок на эту конкретную проблему.

Я выделил, что это действительно проблема в моем коде: например, если я использую растровое изображение источника, которое имеет 16 цветов (4 бит), оно работает; если я использую 32-битное изображение, он создает полностью черную маску.

Есть ли альтернативный метод, который я должен использовать в случае 32-битных цветных изображений? Есть ли проблема с альфа-каналом, который переопределяет нормальное поведение вышеупомянутого метода?

Спасибо за любую помощь, которую вы, возможно, должны будете предложить!

ADDENDUM: Мне все еще не удается найти технику, которая создает допустимый монохромный растровый рисунок для моего GDI + созданного исходного растрового изображения.

Я несколько смягчил свою конкретную проблему, просто не создавая монохромную битовую маску вообще, и вместо этого я использую TransparentBlt(), который, кажется, правильно это понимает (но я не знаю, что они делают внутри это совсем другое, что позволяет им правильно маскировать изображение).

Это может быть полезно иметь очень хорошую, рабочую функцию:

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

Где она всегда создает действительную маску прозрачности, независимо от глубины цвета hSource.

Идеи?

+3

GDI застрял в 24bpp. TransparentBlt() немного необычен, документируется поддержка 32bpp. Время переместиться в GDI + возможно. –

ответ

3

Вы не можете сделать это, если есть альфа-канал. COLORREF использует верхние 8 бит для ряда целей, в том числе указывая, что ниже или ниже нижние 3 байта представляют собой индекс таблицы цветов в текущую палитру или триплет RGB. Таким образом, вы не можете указать ничего, кроме 0x00, в верхнем байте clrTransparency.

Если у вас есть альфа-растровое изображение, то для GDI, который остается «не знаком» с альфа-каналом, нет никакого разумного способа сравнить 24-битный BkColor с 32-битными пикселями в растровом изображении.

Я ожидал бы, что GDI обработает альфа-канал в растровых изображениях 32bpp как «зарезервировано» и будет успешно сравнивать пиксели, где зарезервированный канал равен нулю. т. е. ваш цвет маски должен быть полностью прозрачным, чтобы иметь шанс преуспеть. (и, если вы сделали законное премультипликативное растровое изображение, это означает, что значения RGV также будут равны нулю, скорее ограничивая ваш выбор цветов маски: P)

+0

В этом конкретном случае проблема заключается в том, что я начинаю с 4-битного битового растра. Затем, чтобы отобразить его красивым способом при отключении, я хотел бы сделать его рендеринг по шкале серого, а затем использовать его как лицо кнопки (используя маскированную технологию прозрачности, как раньше). Но код, который я использую для создания серой шкалы, основан на GDI +, который, как я подозреваю, создает 32-битное цветное изображение, а не 24-битное цветное изображение. – Mordachai

+1

@Mordachai: Учитывая то, что вы только что описали, можете ли вы сделать маску из исходного 4-битного изображения и использовать его с созданным GDI? –

+0

Мне нравится идея для моих целей. Но меня все равно интересовал общий «способ создания монохромной битовой маски для * ANY * source HBITMAP». – Mordachai

0

Альтернативным методом будет сканирование пикселей самостоятельно и генерация и монохромность растровое изображение на основе исходного цвета (или альфа-альфа от порога).

Обратите внимание, что если вы используете GDI +, то в зависимости от операции пиксели могут быть сглажены, в результате ни один из них не является точным совпадением для вашего «прозрачного» цвета.

+0

Я сохранил изображение с серой шкалой GDI + в виде 32-битной глубины PNG, а затем выбрал пиксели в Paint. Они в порядке. Тем не менее, я дважды проверял полученный HBITMAP, который создает GDI + (через Bitmap :: GetHBitmap()), и он действительно всегда имеет 32-битную глубину, несмотря на то, что базовый экземпляр Bitmap является PixelFormat24bppRGB). – Mordachai

3

Может делать :)
Как указано в «Крисе Бекке» выше, GDI может сравниться, только если зарезервированный канал альфа-канала равен нулю.
HBITMAP получен из BITMAP :: GetHBITMAP() возвращает HBITMAP с альфа-каналом, все установлены в 0xFF.
Это должно быть 0x00 для SetBkColor() Сравнение с работой.
Следовательно, Soln: Loop через каждый пиксель и установите альфа-компонент в ноль.

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

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. 

На моей машине это выполняется быстрее, чем двойная петля из ответа Уджваля.

+0

Спасибо. Хорошо знать. – Mordachai

+0

Просто, чтобы сделать этот метод более ясным, a. 3) SelectObject выбирает растровое изображение, созданное с помощью CreateDIBSection, в новый DC, созданный в 1) b. Для создания маски вам нужно убедиться, что вы вызываете SetBkColor на новом 24-битном DC, созданном в 1), я случайно установил SetBkColor на 32-битный DC, и потребовалось некоторое время для устранения неполадок. – frank