Спасибо всем кто откликнулся, но разобрался сам. Функция LoadBitmap загружает изображение в память и возвращает только его handle. Далее функцией GetObject можно получить информацию о загруженном изображении в структуре BITMAP, но в ней указатель на массив точек будет пустой. Я воспользовался функцией LoadImage, добавленной в замен устаревшей LoadBittam. Среди прочих параметров в ней можно указать флаг загрузки и если загрузить изображение с флагом LR_CREATEDIBSECTION, то будет создана DIB секция в памяти и указатель на нее будет лежать в структуре BITMAP в параметре bmBits.
hBitmap = (HBITMAP) LoadImage(
hInstance,
MAKEINTRESOURCE(IDB_BITMAP1),
IMAGE_BITMAP, // загружаем BITMAP
0, // ширина
0, // высота
LR_CREATEDIBSECTION // флаг загрузки
);
Подробнее о LoadImage тут.
Функция AlphaBlend принимает предъумноженное изображение (premultiplied) и просто загрузить изображение не прокатит. Так как мы создали, при загрузке изображения, DIB секцию, то произведем предъумножение каждой компоненты цвета (32bpp) на коэффициент alpha-канала по формуле:
коэффициент alpha: float fAlpha = (Pixel[i] >> 24) / 255.0f;
а затем перебирая точки умножаем все на этот коэффициент. Привожу код:
// Производит пред-умножение точек на альфа канал в DIB секции изображения
void PreMultiplyBitmapAlpha(HBITMAP hBmp)
{
// получаем информацию об загруженном bitmap
BITMAP bm = { 0 };
GetObject(hBmp, sizeof(BITMAP), &bm);
// для удобства записывает указатель на массив точек 0xARGB / 0xB 0xG 0xR 0xA
DWORD* Pixel = (DWORD*)bm.bmBits;
for (LONG i = 0; i < bm.bmHeight * bm.bmWidth; i++)
{
// вычисляем коэффициент альфа канала
float fAlpha = (Pixel[i] >> 24) / 255.0f;
// умножаем каждую компоненту пикселя на коэффициент
// альфа-канала и перезаписываем
Pixel[i] = (Pixel[i] & 0xFF000000) | // 0xaa000000
(BYTE(GetBValue(Pixel[i]) * fAlpha) << 16) | // 0x00rr0000
(BYTE(GetGValue(Pixel[i]) * fAlpha) << 8) | // 0x0000gg00
(BYTE(GetRValue(Pixel[i]) * fAlpha)); // 0x000000bb
}
}
Примечание: в качестве параметра принимает hbitmap изображения с DIB секцией
В завершении скармливаем обработанное изображение в AlphaBlend :
// создаем совместимый DC с DC окна и связываем его с изображением
// с пред-умноженным альфа-каналом
HDC hSrcDC = CreateCompatibleDC(hDC);
SelectObject(hSrcDC, hBitmap);
BITMAP bm = { 0 };
GetObject(hBitmap, sizeof(BITMAP), &bm);
BLENDFUNCTION bf = { 0 };
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 0xff; // общая прозрачность
bf.AlphaFormat = AC_SRC_ALPHA; // используется прозрачность
// альфа канала для каждой точки
// выводим на экран с учетом альфа-канала
AlphaBlend(
hDC, 0, 20, bm.bmWidth, bm.bmHeight,
hSrcDC, 0, 0, bm.bmWidth, bm.bmHeight,
bf
);
DeleteDC(hSrcDC);
Примечание: если не хочется тянуть функцию AlphaBlend из библиотеки msimg32.dll, можно использовать ее аналог из все той же библиотеки gdi32.dll
но с префиксом Gdi: GdiAlphaBlend, GdiTransparentBlt, GdiGradientFill и т.д.
Результат:
