Как создать Gdiplus:: Bitmap из HBITMAP, сохранив информацию об альфа-канале?
Вопрос
Когда я создаю новый Gdiplus:: Bitmap с помощью функции Bitmap:: FromHBITMAP, результирующее растровое изображение непрозрачно - ни одна частичная прозрачность из исходной HBITMAP не сохраняется.
Есть ли способ создать Gdiplus:: Bitmap из HBITMAP, который передает данные альфа-канала?
Решение 2
Оказывается, что GDI + никогда не передает альфа-канал при создании растрового изображения из HBITMAP.
Ответ заключается в том, чтобы:
- Используйте GetObject, передающий РАСТРОВОЕ изображение и HBITMAP, чтобы получить ширину и высоту (и, если входное растровое изображение является DIB, пиксельные данные) входного HBITMAP.
- Создайте растровое изображение нужного размера в 32-битном формате PARGB pixel.
- Используйте блокирующие биты, чтобы получить доступ к памяти pixelData вашего нового растрового изображения.
- Если вы получили пиксели из GetObject, скопируйте значения ARGB с помощью memcpy.
- Вызовите UnlockBits для нового растрового изображения.
В моем случае формат входного HBITMAP является правильным для выполнения прямого преобразования входных растровых пиксельных данных в новые растровые пиксельные данные.
Если вы не получили входные пиксельные данные из GetObject, используйте GetDIBits, чтобы получить копию в правильном формате.
Другие советы
Я думаю, что рабочий код более полезен, чем инструкции, поэтому:
#include <GdiPlus.h>
#include <memory>
Gdiplus::Status HBitmapToBitmap( HBITMAP source, Gdiplus::PixelFormat pixel_format, Gdiplus::Bitmap** result_out )
{
BITMAP source_info = { 0 };
if( !::GetObject( source, sizeof( source_info ), &source_info ) )
return Gdiplus::GenericError;
Gdiplus::Status s;
std::auto_ptr< Gdiplus::Bitmap > target( new Gdiplus::Bitmap( source_info.bmWidth, source_info.bmHeight, pixel_format ) );
if( !target.get() )
return Gdiplus::OutOfMemory;
if( ( s = target->GetLastStatus() ) != Gdiplus::Ok )
return s;
Gdiplus::BitmapData target_info;
Gdiplus::Rect rect( 0, 0, source_info.bmWidth, source_info.bmHeight );
s = target->LockBits( &rect, Gdiplus::ImageLockModeWrite, pixel_format, &target_info );
if( s != Gdiplus::Ok )
return s;
if( target_info.Stride != source_info.bmWidthBytes )
return Gdiplus::InvalidParameter; // pixel_format is wrong!
CopyMemory( target_info.Scan0, source_info.bmBits, source_info.bmWidthBytes * source_info.bmHeight );
s = target->UnlockBits( &target_info );
if( s != Gdiplus::Ok )
return s;
*result_out = target.release();
return Gdiplus::Ok;
}