Как создать Gdiplus :: Bitmap из HBITMAP, сохранив информацию об альфа-канале?

Когда я создаю новый Gdiplus :: Bitmap с помощью функции Bitmap :: FromHBITMAP, результирующее растровое изображение непрозрачно - частичная прозрачность исходного HBITMAP не сохраняется.

Есть ли способ создать Gdiplus :: Bitmap из HBITMAP, который передает данные альфа-канала?

Вы точно знаете, что у HBITMAP есть альфа-канал для начала? Например, вы создали его как DIB с BI_RGB и 32bpp или каким-то другим способом?

Johann Gerell 03.12.2008 13:33

Да, прозрачность есть. Он прекрасно рисуется с помощью функции :: AlphaBlend ().

mackenir 03.12.2008 16:44

(Я создал его на C#, используя новое изображение Bitmap (строковое имя файла) и вызов GetHBitmap () для объекта растрового изображения .NET)

mackenir 03.12.2008 16:46
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
7
3
13 773
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Оказывается, GDI + никогда не использует альфа-канал при создании Bitmap из HBITMAP.

Ответ таков:

  • Используйте GetObject, передавая BITMAP и HBITMAP, чтобы получить ширину и высоту (и, если входное растровое изображение является DIB, данными пикселей) входного HBITMAP.
  • Создайте растровое изображение правильного размера с 32-битным форматом пикселей PARGB.
  • Используйте LockBits, чтобы получить доступ к памяти pixelData вашего нового Bitmap.
  • Если вы получили пиксели из GetObject, скопируйте значения ARGB с помощью memcpy.
  • Вызовите UnlockBits для нового Bitmap.

В моем случае формат входного HBITMAP является правильным для выполнения прямого memcpy из входных данных пикселей растрового изображения в новые данные пикселей растрового изображения.

Если вы не получили входные данные пикселей из 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;
}

У меня была аналогичная проблема с CBitmap, из которого я получил HBITMAP. В этом случае ::GetObject() оставил source_info.bmBits установленным в NULL. Я мог бы решить эту проблему, позвонив в myCBitmapPtr->GetBitmapBits(source_info.bmWidthBytes * source_info.bmHeight, target_info.Scan0).

foraidt 19.08.2014 17:32

Кстати, возвращаемые значения хорошо проверены в вашем примере, но если source_info.bmBits равен NULL, есть нарушение прав доступа при вызове CopyMemory().

foraidt 19.08.2014 17:35

Другие вопросы по теме