can i change the HBITMAP structure for be transparent?
because the gif's files are show me a black background color.

Recommended Answers

All 11 Replies

sorry, in these case i don't have HDC

The first thing you need to do is select the HBITMAP into a MemoryDC. Then you cna use the AlphaBlend function to draw it to the WindowDC.

If the MemoryDC is NOT compatible with the WindowDC, this will fail! In that case, you can use CreateCompatibleBitmap(WindowDC, width, height), copy the existing bitmap to the new bitmap, draw it and free the new bitmap.

However, that is left as an exercise for you..

void DrawAlphaGDI(HDC DC, Gdiplus::Rect rect)
{
    HGDIOBJ obj = SelectObject(memDC, hBmp);
    AlphaBlend(DC, rect.X, rect.Y, rect.Width, rect.Height, memDC, 0, 0, Width, Height, BlendFunc); //You need to create a blend-function..
    SelectObject(memDC, obj);
}

If the source has no alpha channel, it will NOT be transparent unless you specify what colour to make transparent. For that, you can use TransparentBlt.

Image <-- Transparent image (png)

Results <-- Transparent Drawing..

i did i nice way for my label control and works:

void DrawHBITMAPtoHDC(HBITMAP hBitmap, HDC hdc)
{
    BITMAP bm;
    HDC MemDCExercising = CreateCompatibleDC(hdc);
    HBITMAP oldbitmap =(HBITMAP) SelectObject(MemDCExercising, hBitmap);
    GetObject(hBitmap,sizeof(bm),&bm);
    TransparentBlt(hdc, 0, 0, bm.bmWidth , bm.bmHeight, MemDCExercising, 0, 0,bm.bmWidth , bm.bmHeight,GetPixel(MemDCExercising,0,0) );
    SelectObject(MemDCExercising,oldbitmap);
    DeleteDC(MemDCExercising);
}
//on label paint message:
case WM_PAINT:
            {
                PAINTSTRUCT  ps;
                BeginPaint(inst->hwnd, &ps);
                if(inst->Paint==NULL)
                {
                    RECT f;
                    HDC hdc=GetDC(inst->hwnd);//getting the control HDC
                    GetClientRect(inst->hwnd,&f);//getting the
                    HBRUSH s=CreateSolidBrush(inst->clrBackColor);
                    HBRUSH oldBrush=(HBRUSH)SelectObject(hdc,(HBRUSH)s);
                    if (inst->clrBackColor==-1)
                    {
                        //hide, copy the parent control and show the control again
                        ShowWindow(inst->hwnd,SW_HIDE);
                        BitBlt(hdc,0,0,f.right-f.left,f.bottom-f.top,GetDC(GetParent(inst->hwnd)),inst->intLeft,inst->intTop,SRCCOPY);
                        ShowWindow(inst->hwnd,SW_SHOW);
                    }
                    else
                        FillRect(hdc,&f,s);
                    DrawHBITMAPtoHDC(inst->hBitmap,hdc);
                    SetBkMode(hdc,TRANSPARENT);
                    char *text=(char*)inst->strCaption.c_str();
                    SetTextColor(hdc,inst->clrTextColor );
                    DrawTextEx(hdc,text,-1,&f,DT_CENTER,NULL);
                    SelectObject(hdc,(HBRUSH)oldBrush);
                    DeleteObject(s);
                }
                EndPaint(inst->hwnd, &ps);

i'm trying the same tecnic with menus, but, for now, without sucess.

 void bitmap(image imgImage)
    {
        BITMAP bm;
        HDC MemDCExercising = CreateCompatibleDC(NULL);
        GetObject((HBITMAP)imgImage,sizeof(bm),&bm);
        HBITMAP outbitmap=CreateBitmap(bm.bmWidth,bm.bmHeight,1,32,NULL);
        HBITMAP oldbitmap =(HBITMAP) SelectObject(MemDCExercising, outbitmap);
        DrawHBITMAPtoHDC(imgImage,MemDCExercising);
        SelectObject(MemDCExercising,oldbitmap);
        DeleteDC(MemDCExercising);

        HMENU hMenu = NULL;
        if(primeiromenu)
            hMenu = mnuBar;
        else
            hMenu = MenuHandle;
        SetMenuItemBitmaps(hMenu,ID,MF_BYCOMMAND,(HBITMAP)outbitmap ,(HBITMAP)outbitmap);
    }

Everytime you do GetDC, you are leaking a DC. You NEED to ReleaseDC.

Even if you do DC = GetDC(NULL) you need to do ReleaseDC(NULL, DC);. If you do DC = GetDC(hwnd) you need to do ReleaseDC(hwnd, DC);.

In the above code, you don't need GetDC.. Use the DC that is inside the PaintStruct.

Secondly, for usage with menu, it must be COMPATIBLE.. You can't just use CreateBitmap and hope that the DC's compatible..

HBITMAP bitmap(image imgImage) //creates a copy of imgImage or whatever is passed to this function! Beware!
{
    BITMAP bm;
    GetObject((HBITMAP)imgImage, sizeof(bm), &bm);

    HDC DC = GetDC(NULL);
    HDC MemDCExercising = CreateCompatibleDC(DC); //Create a DC compatible with our Display/Monitor.. 32-bit.
    HBITMAP outbitmap = CreateCompatibleBitmap(DC, bm.bmWidth, bm.bmHeight); //create a bitmap that is compatible with our DC.
    HBITMAP oldbitmap = (HBITMAP) SelectObject(MemDCExercising, outbitmap);


    DrawHBITMAPtoHDC(imgImage, MemDCExercising); //good.

    SelectObject(MemDCExercising, oldbitmap);
    DeleteDC(MemDCExercising);
    ReleaseDC(NULL, DC); //good.

    HMENU hMenu = NULL;
    if(primeiromenu)
        hMenu = mnuBar;
    else
        hMenu = MenuHandle;
    SetMenuItemBitmaps(hMenu,ID,MF_BYCOMMAND,(HBITMAP)outbitmap ,(HBITMAP)outbitmap);

    return outbitmap; //we return it so that later we can call DeleteObject to free its memory.
}

The only thing I'm not sure about is if the DrawHBITMAPToHDC call will work. But try it and let me know.

the image is showed, but not transparent :(

void bitmap(image imgImage)
    {
        DeleteObject(outbitmap);
        BITMAP bm;
        GetObject((HBITMAP)imgImage,sizeof(bm),&bm);
        HDC DC = GetDC(NULL);
        HDC MemDCExercising = CreateCompatibleDC(DC);
        outbitmap=CreateCompatibleBitmap(DC, bm.bmWidth, bm.bmHeight);
        HBITMAP oldbitmap =(HBITMAP) SelectObject(MemDCExercising, outbitmap);
        DrawHBITMAPtoHDC(imgImage,MemDCExercising);
        SelectObject(MemDCExercising,oldbitmap);
        DeleteDC(MemDCExercising);
        ReleaseDC(NULL, DC);

        HMENU hMenu = NULL;
        if(primeiromenu)
            hMenu = mnuBar;
        else
            hMenu = MenuHandle;
        SetMenuItemBitmaps(hMenu,ID,MF_BYCOMMAND,(HBITMAP)imgImage ,(HBITMAP)imgImage);
    }

the outbitmap is a global variable and deleted, too, on destructor.

sorry i have several mistakes on last code

i continue with problems. the HBITMAP isn't copyed to HDC:

void bitmap(image imgImage)
    {
        DeleteObject(outbitmap);
        BITMAP bm;
        RECT f={0,0,100,100};
        GetObject((HBITMAP)imgImage, sizeof(bm), &bm);
        HDC DC = GetDC(NULL);
        HDC MemDCExercising = CreateCompatibleDC(DC); //Create a DC compatible with our Display/Monitor.. 32-bit.
        outbitmap = CreateCompatibleBitmap(MemDCExercising, bm.bmWidth, bm.bmHeight); //create a bitmap that is compatible with our DC.
        HBITMAP oldbitmap = (HBITMAP) SelectObject(MemDCExercising, (HBITMAP)outbitmap);
        HDC MemDCExercising2 = CreateCompatibleDC(DC);
        HBITMAP oldbitmap2 = (HBITMAP) SelectObject(MemDCExercising2, (HBITMAP)imgImage);
        TransparentBlt(MemDCExercising, 0, 0, bm.bmWidth , bm.bmHeight, MemDCExercising2, 0, 0,bm.bmWidth , bm.bmHeight,GetPixel(MemDCExercising2,0,0) );

        DrawHBITMAPtoHDC((HBITMAP)imgImage, MemDCExercising); //not showed in these situation
        //maybe the memory DC or the HBITMAP selection is wrong
        DrawTextEx(MemDCExercising,"hello world",-1,&f,DT_CENTER,NULL);//is showed
        SelectObject(MemDCExercising, oldbitmap);
        DeleteDC(MemDCExercising);
        ReleaseDC(NULL, DC); //good.
        HMENU hMenu = NULL;
        if(primeiromenu)
            hMenu = mnuBar;
        else
            hMenu = MenuHandle;
        SetMenuItemBitmaps(hMenu,ID,MF_BYCOMMAND,(HBITMAP)outbitmap ,(HBITMAP)outbitmap);
    }
void Draw(HBITMAP hBitmap, HDC hdc)
{
    BITMAP bm;
    GetObject(hBitmap, sizeof(bm), &bm);
    HDC MemDCExercising = CreateCompatibleDC(hdc);
    HGDIOBJ obj = SelectObject(MemDCExercising, hBitmap);
    BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, MemDCExercising, 0, 0, SRCCOPY);
    SelectObject(MemDCExercising, obj);
    DeleteDC(MemDCExercising);
}

void DrawTransparent(HBITMAP hBitmap, HDC hdc, COLORREF Colour)
{
    BITMAP bm;
    GetObject(hBitmap, sizeof(bm), &bm);
    HDC MemDCExercising = CreateCompatibleDC(hdc);
    HGDIOBJ obj = SelectObject(MemDCExercising, hBitmap);
    TransparentBlt(hdc, 0, 0, bm.bmWidth , bm.bmHeight, MemDCExercising, 0, 0, bm.bmWidth , bm.bmHeight, Colour);
    SelectObject(MemDCExercising, obj);
    DeleteDC(MemDCExercising);
}

HBITMAP Copy(HBITMAP hBmp)
{
    BITMAP bm;
    GetObject(hBmp, sizeof(bm), &bm);

    HDC DC = GetDC(NULL);
    HDC MemDC = CreateCompatibleDC(DC);
    HBITMAP result = CreateCompatibleBitmap(DC, bm.bmWidth, bm.bmHeight);

    HGDIOBJ obj = SelectObject(MemDC, result);
    Draw(hBmp, MemDC);

    SelectObject(MemDC, obj);
    DeleteDC(MemDC);
    return result;
}

HBITMAP TransparentCopy(HBITMAP hBmp, COLORREF Colour)
{
    BITMAP bm;
    GetObject(hBmp, sizeof(bm), &bm);

    HDC DC = GetDC(NULL);
    HDC MemDC = CreateCompatibleDC(DC);
    HBITMAP result = CreateCompatibleBitmap(DC, bm.bmWidth, bm.bmHeight);

    HGDIOBJ obj = SelectObject(MemDC, result);
    DrawTransparent(hBmp, MemDC, Colour);

    SelectObject(MemDC, obj);
    DeleteDC(MemDC);
    return result;
}

Example (same as you were trying to do):

Image imgImage = Image("blah.bmp");

HBITMAP global = TransparentCopy((HBITMAP)imgImage, RGB(255, 0, 0));

SetMenuItemBitmaps(......., global, global);

Then set the menu bitmap to whatever you want.. NOTE: I could not get the above to draw black as transparent. I have no idea why.. All other colours work except black :S. Also note that I did not try any of the above on menus..

please try with menus. and with gif files(where i see the problem)

Try this:

For bitmaps, png's, gif's that DO NOT have an alpha channel:

bool isSimilar(COLORREF A, COLORREF B, unsigned int t)
{
    unsigned char AR = GetRValue(A);
    unsigned char AG = GetGValue(A);
    unsigned char AB = GetBValue(A);

    unsigned char BR = GetRValue(B);
    unsigned char BG = GetGValue(B);
    unsigned char BB = GetBValue(B);
    return static_cast<unsigned int>((AR - BR) * (AR - BR) + (AG - BG) * (AG - BG) + (AB - BB) * (AB - BB)) <= (t * t);
}


void setAlphas(HBITMAP hBmp, int w, int h, COLORREF TransparentColour, COLORREF BackgroundColour, unsigned int Tolerance)
{
    BITMAPINFOHEADER bminfoheader;
    ZeroMemory(&bminfoheader, sizeof(BITMAPINFOHEADER));
    bminfoheader.biSize        = sizeof(BITMAPINFOHEADER);
    bminfoheader.biWidth       = w;
    bminfoheader.biHeight      = h;
    bminfoheader.biPlanes      = 1;
    bminfoheader.biBitCount    = 32;
    bminfoheader.biCompression = BI_RGB;

    HDC DC = CreateCompatibleDC(0);
    unsigned char* pPixels = new unsigned char[w * h * 4];
    memset(pPixels, 0, w * h * 4);

    GetDIBits(DC, hBmp, 0, h, pPixels, (BITMAPINFO*) &bminfoheader, DIB_RGB_COLORS);

    unsigned char* p = pPixels;
    for (int i = 0; i < h; ++i)
    {
        for (int j = 0; j < w; ++j)
        {
            unsigned char* B = p++;
            unsigned char* G = p++;
            unsigned char* R = p++;
            unsigned char* A = p++;

            if (isSimilar(RGB(*R, *G, *B), TransparentColour, Tolerance))
            {
                *R = GetRValue(BackgroundColour);
                *G = GetGValue(BackgroundColour);
                *B = GetBValue(BackgroundColour);
                *A = 0;
            }
        }
    }

    SetDIBits(DC, hBmp, 0, h, pPixels, (BITMAPINFO*) &bminfoheader, DIB_RGB_COLORS);
    DeleteDC(DC);
    delete[] pPixels;
}



case WM_PAINT:
{
    static AutoGDI* gdi = new AutoGDI(L"C:/Users/Brandon/Desktop/small.png");
    setAlphas(gdi->getHBITMAP(), 50, 63, RGB(0, 0, 0), RGB(240, 240, 240), 10); //although it's not costly, you should try to only call this once..
    SetBitmapMenu(gdi->getHBITMAP());
}
break;

In the above code:

(0, 0, 0) is the colour that will be considered TRANSPARENT!
(240, 240, 240) is the background colour of the menu.
10 is the threshold/tolerance to determine whether or not two colours match. 0 is the lowest threshold.

Play around with the threshold as much as you want and decide what's best for you.

---------------------------------------------------------------------

For bitmaps, png's, or gifs that ALREADY HAVE an alpha channel:

void setAlphasWithChannel(HBITMAP hBmp, int w, int h, COLORREF BackgroundColour)
{
    BITMAPINFOHEADER bminfoheader;
    ZeroMemory(&bminfoheader, sizeof(BITMAPINFOHEADER));
    bminfoheader.biSize        = sizeof(BITMAPINFOHEADER);
    bminfoheader.biWidth       = w;
    bminfoheader.biHeight      = h;
    bminfoheader.biPlanes      = 1;
    bminfoheader.biBitCount    = 32;
    bminfoheader.biCompression = BI_RGB;

    HDC DC = CreateCompatibleDC(0);
    unsigned char* pPixels = new unsigned char[w * h * 4];
    memset(pPixels, 0, w * h * 4);

    GetDIBits(DC, hBmp, 0, h, pPixels, (BITMAPINFO*) &bminfoheader, DIB_RGB_COLORS);

    unsigned char* p = pPixels;
    for (int i = 0; i < h; ++i)
    {
        for (int j = 0; j < w; ++j)
        {
            unsigned char* B = p++;
            unsigned char* G = p++;
            unsigned char* R = p++;
            unsigned char* A = p++;

            if (*A == 0)
            {
                *R = GetRValue(BackgroundColour);
                *G = GetGValue(BackgroundColour);
                *B = GetBValue(BackgroundColour);
            }
        }
    }

    SetDIBits(DC, hBmp, 0, h, pPixels, (BITMAPINFO*) &bminfoheader, DIB_RGB_COLORS);
    DeleteDC(DC);
    delete[] pPixels;
}



case WM_PAINT:
{
    static AutoGDI* gdi = new AutoGDI(L"C:/Users/Brandon/Desktop/small.png");
    setAlphas(gdi->getHBITMAP(), 50, 63, RGB(240, 240, 240)); //although it's not costly, you should try to only call this once..
    SetBitmapMenu(gdi->getHBITMAP());
}
break;

DO NOT forget to delete your AutoGDI or image instance when the application closes!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.