3
votes

SOLVED: Current code sample:

HBITMAP TwoBitmap(HDC &hdc, RECT &rc)
{
    HDC hdcmem = CreateCompatibleDC(hdc);
    HBITMAP hbitmap = CreateCompatibleBitmap(hdc, rc.right-rc.left, rc.bottom-rc.top);
    SelectObject(hdcmem, hbitmap);

    HBRUSH hBrush = GetSysColorBrush(2);
    FillRect(hdcmem, &rc, hBrush);
    DeleteObject((HBRUSH)hBrush);

    DeleteDC(hdcmem);

    return hbitmap;
}

void CreateTransparentBitmap(HBITMAP &hBitmap)
{
    BITMAP TemporaryBitmap;
    GetObject(hBitmap, sizeof(BITMAP), &TemporaryBitmap);

    HDC MemoryDC = CreateCompatibleDC(NULL);

    BITMAPINFO BitmapInfo;
    ZeroMemory(&BitmapInfo,sizeof(BITMAPINFO));
    BitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    BitmapInfo.bmiHeader.biWidth = TemporaryBitmap.bmWidth;
    BitmapInfo.bmiHeader.biHeight = TemporaryBitmap.bmHeight;
    BitmapInfo.bmiHeader.biPlanes = 1;
    BitmapInfo.bmiHeader.biBitCount = 32;
    BitmapInfo.bmiHeader.biCompression = BI_RGB;

    RGBQUAD* pArgb = NULL;
    HBITMAP hTemporaryBitmap = CreateDIBSection(MemoryDC, &BitmapInfo, DIB_RGB_COLORS, (void**)&pArgb, NULL, 0);

    GetDIBits(MemoryDC, hBitmap, 0, BitmapInfo.bmiHeader.biHeight, pArgb, &BitmapInfo, DIB_RGB_COLORS);

    for (int i = 0; i < BitmapInfo.bmiHeader.biWidth * BitmapInfo.bmiHeader.biHeight; i++)
        pArgb[i].rgbReserved = 255;

    DeleteDC(MemoryDC);

    DeleteObject(hBitmap);
    hBitmap = hTemporaryBitmap;
}

case WM_PAINT:
    {
        PAINTSTRUCT p;
        HDC hDC = BeginPaint(hWnd, &p);
        HDC hdcmem = CreateCompatibleDC(hDC);

        HBITMAP hImage = TwoBitmap(hDC, p.rcPaint);

        CreateTransparentBitmap(hImage);

        SelectObject(hdcmem, hImage);

        BLENDFUNCTION bfn;
        bfn.BlendOp = AC_SRC_OVER;
        bfn.BlendFlags = 0;
        bfn.SourceConstantAlpha = 10;
        bfn.AlphaFormat = AC_SRC_ALPHA;

        AlphaBlend(hDC, 0, 0, 100, 64, hdcmem, 0, 0, 100, 64, bfn);

        bfn.SourceConstantAlpha = 80;
        AlphaBlend(hDC, 200, 0, 100, 64, hdcmem, 0, 0, 100, 64, bfn);

        bfn.SourceConstantAlpha = 255;
        AlphaBlend(hDC, 400, 0, 100, 64, hdcmem, 0, 0, 100, 64, bfn);

        BitBlt(hDC, 0, 100, 100, 64, hdcmem, 0, 0, SRCCOPY);

        DeleteDC(hdcmem);

        DeleteObject(hImage);

        EndPaint(hWnd, &p);
    }
    break;

For this example I have a simple bitmap created using CreateCompatibleBitmap():

HBITMAP TwoBitmap(HDC &hdc, RECT &rc)
{
    HDC hdcmem = CreateCompatibleDC(hdc);
    HBITMAP hbitmap = CreateCompatibleBitmap(hdc, rc.right-rc.left, 
                                             rc.bottom-rc.top);
    SelectObject(hdcmem, hbitmap);

    HBRUSH hBrush = GetSysColorBrush(3);
    FillRect(hdcmem, &rc, hBrush);
    DeleteObject((HBRUSH)hBrush);

    DeleteDC(hdcmem);

    return hbitmap;
}

Now, what I am trying to achieve is to add alpha channel to this bitmap (if it doesn't have it already). Using the code below I try to create a 32 bit bitmap and then copy old bitmap into this new one. And finally I print out new bitmap to screen using AlphaBlend() and BitBlt() functions and as usual I get monochromatic alpha blend images and perfectly fine BitBlt image.

So there goes my question - what am I missing, doing wrong? I'm pretty lost here. My code (don't mind GDI leaks):

EDIT:

Thanks to PhoenixX_2 I was able to solve the mystery, all I needed was to set Alpha bit to 255. Here is my code below, keep in mind that it isn't leak-free.

PAINTSTRUCT p;
HDC hDC = BeginPaint(hWnd, &p);

HDC BufferDC = CreateCompatibleDC(NULL);

BITMAPINFO BufferInfo;
ZeroMemory(&BufferInfo,sizeof(BITMAPINFO));
BufferInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
BufferInfo.bmiHeader.biWidth = p.rcPaint.right-p.rcPaint.left;
BufferInfo.bmiHeader.biHeight = p.rcPaint.bottom-p.rcPaint.top;
BufferInfo.bmiHeader.biPlanes = 1;
BufferInfo.bmiHeader.biBitCount = 32;
BufferInfo.bmiHeader.biCompression = BI_RGB;
RGBQUAD* pArgb;
HBITMAP BufferBitmap = CreateDIBSection(BufferDC, &BufferInfo, DIB_RGB_COLORS,
                                       (void**)&pArgb, NULL, 0);

HBITMAP hImage  =  TwoBitmap(hDC, p.rcPaint);

GetDIBits(BufferDC, hImage, 0, BufferInfo.bmiHeader.biHeight, pArgb, 
          &BufferInfo, DIB_RGB_COLORS);

//----------------------------------the part I was missing
for (int i = 0; i < BufferInfo.bmiHeader.biWidth 
     * BufferInfo.bmiHeader.biHeight; i++)
pArgb[i].rgbReserved = 255;
//----------------------------------

SelectObject(BufferDC, BufferBitmap);

BLENDFUNCTION bfn;
bfn.BlendOp = AC_SRC_OVER;
bfn.BlendFlags = 0;
bfn.SourceConstantAlpha = 10;
bfn.AlphaFormat = AC_SRC_ALPHA;

AlphaBlend(hDC, 0, 0, 100, 64, BufferDC, 0, 0, 100, 64, bfn);

bfn.SourceConstantAlpha = 80;
AlphaBlend(hDC, 200, 0, 100, 64, BufferDC, 0, 0, 100, 64, bfn);

bfn.SourceConstantAlpha = 255;
AlphaBlend(hDC, 400, 0, 100, 64, BufferDC, 0, 0, 100, 64, bfn);

BitBlt(hDC, 0, 100, 100, 64, BufferDC, 0, 0, SRCCOPY);

DeleteDC(BufferDC);

DeleteObject((HBITMAP)BufferBitmap);

EndPaint(hWnd, &p);
1
it is similar, however I have a bitmap that I need to add alpha channel and this one already creates it on spot.FrogTheFrog

1 Answers

3
votes

I really recommend you use a library like FreeImage. The benefit of the library, besides it being fairly lightweight and extremely open license, is the fact that it'll handle all image types easily. Then converting from any format (including different bitmap formats) to 32bit is trivial. So is rendering and other tasks.

Besides that, if you'ren't interested in using a library, is just manipulate the pixel data yourself. Converting from 24bit to 32bit is fairly trivial with two points and casting. Something like this should do:

uint8_t* pArgb;
uint8_t* pRgb;

GetDIBits(BufferDC, hImage, 0, BufferInfo.bmiHeader.biHeight, pRgb, &BufferInfo, DIB_RGB_COLORS);

pArgb = (uint8_t*)malloc(4 * BufferInfo.bmiHeader.biWidth * BufferInfo.bmiHeader.biHeight);
for (int i = 0; i < BufferInfo.bmiHeader.biWidth * BufferInfo.bmiHeader.biHeight; ++i) {
    *(int*)pArgb = 0xff000000 | (*(int*)(pRgb) >> 8);
    pArgb += 4;
    pRgb += 3;
}