Как нарисовать прозрачный BMP с помощью GDI +

В настоящее время я редактирую старый код GDI для использования GDI + и столкнулся с проблемой, когда дело доходит до отрисовки файла BMP с прозрачным фоном. В старом коде GDI не использовался какой-либо очевидный дополнительный код для рисования прозрачного фона, поэтому мне интересно, как этого добиться с помощью GDI +.

Мой текущий код выглядит так

HINSTANCE hinstance = GetModuleHandle(NULL);
bmp = Gdiplus::Bitmap::FromResource(hinstance, MAKEINTRESOURCEW(IDB_BMP));
Gdiplus::Graphics graphics(pDC->m_hDC);
graphics.DrawImage(&bmp, posX, posY);

Я также пытался создать новое растровое изображение из ресурса, используя метод клонирования и отрисовывая растровое изображение во вновь созданное, но ни то, ни другое не помогло. Оба раза я использовал PixelFormat32bppPARGB.

Затем я попытался использовать альфа-смешивание, но таким образом все изображение стало прозрачным, а не только фон:

Gdiplus::ColorMatrix clrMatrix = { 
    1.0f, 0.0f, 0.0f, 0.0f, 0.0f,
    0.0f, 1.0f, 0.0f, 0.0f, 0.0f,
    0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
    0.0f, 0.0f, 0.0f, 0.5f, 0.0f,
    0.0f, 0.0f, 0.0f, 0.0f, 1.0f
};

Gdiplus::ImageAttributes imgAttr;
imgAttr.SetColorMatrix(&clrMatrix);

graphics.DrawImage(&bmp, destRect, 0, 0, width(), height(), Gdiplus::UnitPixel, &imgAttr);

Информация о прозрачности уже содержится в изображении, но я не знаю, как применить ее при рисовании изображения. Как этого добиться?


person sigy    schedule 27.07.2012    source источник


Ответы (3)


Самое простое решение - использовать какой-нибудь формат, отличный от BMP.

Вам нужно, чтобы биты содержали альфа-данные, и вам нужно, чтобы растровое изображение было в формате, который имеет альфа-данные. Когда вы загружаете BMP с помощью GDI +, он всегда будет использовать формат без альфа, даже если у BMP есть альфа-канал. Я считаю, что данные есть в битах изображения, но они не используются.

Проблема при клонировании или рисовании в Bitmap PixelFormat32bppPARGB заключается в том, что GDI + преобразует данные изображения в новый формат, что означает отказ от альфа-данных.

Предполагая, что биты загружаются правильно, вам нужно скопировать биты непосредственно в другое растровое изображение с правильным форматом. Вы можете сделать это с помощью Bitmap :: LockBits и Bitmap :: UnlockBits . (Убедитесь, что вы заблокировали каждое растровое изображение с его собственным форматом пикселей, чтобы преобразование не производилось.)

person Esme Povirk    schedule 28.07.2012
comment
Хорошо, действительно кажется, что старый GDI способен рисовать такие изображения без лишних строк кода, а новый GDI + не может делать то же самое без тяжелой дополнительной работы .... печально, но факт - person sigy; 30.07.2012
comment
Как указано в ответе, GDI + может делать это также, вам просто нужно использовать формат изображения, который поддерживает альфа-канал (например, PNG). [Я не сомневаюсь, что вы можете хранить альфа-данные в файле BMP, но не должны. Это ненормально. Если он работает, значит, он работает из-за ошибки в GDI, и вам не следует на это полагаться.] - person BrainSlugs83; 13.01.2015

Поздний ответ, но:

ImageAttributes imAtt;    
imAtt.SetColorKey(Color(255,255,255), Color(255,255,255), ColorAdjustTypeBitmap);  

Сделает white (255,255,255) прозрачным на любом растровом изображении, с которым вы используете этот атрибут изображения.

person Evan Carslake    schedule 09.06.2015
comment
Как использовать это на растровом изображении? - person Paul; 25.01.2019
comment
Передайте этот объект ImageAttributes в одну из перегруженных версий Graphics.DrawImage - person Gautam Jain; 22.02.2021

У меня такая же проблема. Прозрачные BMP не отображаются правильно, и, к сожалению, PNG нельзя загружать напрямую из ресурсов (за исключением добавления небольшого количества кода, который копирует их в поток и загружает из потока). Я хотел избежать этого кода.
В растровых изображениях, которые я использую, также используются только два цвета (фон и логотип). Наличие альфа-канала означает, что мне нужно будет сохранить их с гораздо большей глубиной цвета, а не только с 2-битной глубиной цвета.

Ответ Эвана был именно тем, что я искал :-)

Вместо белого я использую цвет верхнего левого пикселя как прозрачный цвет:

Gdiplus::Color ColourOfTopLeftPixel;
Gdiplus::Status eStatus = m_pBitmap->GetPixel(0, 0, &ColourOfTopLeftPixel);
_ASSERTE(eStatus == Gdiplus::Ok);

// The following makes every pixel with the same colour as the top left pixel (ColourOfTopLeftPixel) transparent.
Gdiplus::ImageAttributes ImgAtt;
ImgAtt.SetColorKey(ColourOfTopLeftPixel, ColourOfTopLeftPixel, Gdiplus::ColorAdjustTypeBitmap);
person Dirksche    schedule 08.10.2015