0

I setup an image list for a listview using ILC_COLOR32 and then used a 32-bit PNG with transparancy and GdiPlus to load it to the image list using ImageList_Add(himl, hbmp, NULL);. I also setup the listview background to be some random color to test transparancy. However I don't understand the results I'm getting in the transparancy areas.

Also, where I can get the transparancy to work, I don't understand why there is a gap between icons?

Can someone explain why I get the results I do and if there a way to get rid of the gap between icons (to fill with the background color)?

//--------------
// this produces white (matches standard window color) in the transparent areas
//--------------
Bitmap* bitmap=Bitmap::FromFile(pfilepath, false);

HBITMAP hbmp;
bitmap->GetHBITMAP(Color(255, 1, 1), &hbmp);
delete bitmap;


//--------------
// this produces white as well
//--------------
Bitmap* bitmap=Bitmap::FromFile(pfilepath, false);

HBITMAP hbmp;
bitmap->GetHBITMAP(Color(255, 1, 1), &hbmp);
delete bitmap;

if (hbmp) {
    CalculateAlphaChannel(hbmp);
}

enter image description here

//--------------
// This produces red in the transparent areas (as expected)
//--------------
Bitmap* bitmap=Bitmap::FromFile(pfilepath, false);

HBITMAP hbmp;
bitmap->GetHBITMAP(Color(255, 1, 1), &hbmp);
delete bitmap;

if (hbmp) {
    BITMAP bm;
    if (::GetObject(hbmp, sizeof(bm), &bm)!=0) {
        if (bm.bmBitsPixel==32 && bm.bmBits) {
            for (int h=0, i=sizeof(COLORREF)-1; h<bm.bmHeight; h++) {
                for (int w=0; w<bm.bmWidth; w++) {
                    ((LPBYTE) bm.bmBits)[i]=0;
                    i+=sizeof(COLORREF);
                }
            }
        }
    }  
}   

enter image description here

//--------------
// this produces black in the transparent areas
//--------------
Bitmap* bitmap=Bitmap::FromFile(pfilepath, false);

HBITMAP hbmp;
bitmap->GetHBITMAP(Color(255, 1, 1), &hbmp);
delete bitmap;

if (hbmp) {

    CalculateAlphaChannel(hbmp);

    BITMAP bm;
    if (::GetObject(hbmp, sizeof(bm), &bm)!=0) {
        if (bm.bmBitsPixel==32 && bm.bmBits) {
            for (int h=0, i=sizeof(COLORREF)-1; h<bm.bmHeight; h++) {
                for (int w=0; w<bm.bmWidth; w++) {
                    ((LPBYTE) bm.bmBits)[i]=0;
                    i+=sizeof(COLORREF);
                }
            }
        }
    }  
}   

enter image description here

To be complete, the listview background color is handle via the NM_CUSTOMDRAW notification message.

INT_PTR CGUIObjControl::ProcessCustomDraw(LPARAM lparam)
{
    LPNMLVCUSTOMDRAW plvcd=(LPNMLVCUSTOMDRAW) lparam;
    switch (plvcd->nmcd.dwDrawStage) {
        case CDDS_PREPAINT:
        {
            //Before the paint cycle begins 
            if (HasTextColor() || GetBrush()) {
                //request notifications for individual listview items
                return CDRF_NOTIFYITEMDRAW;
            }
            break;
        }

        //case CDDS_SUBITEM | CDDS_ITEMPREPAINT:
        case CDDS_ITEMPREPAINT:
        {
            // Before an item is drawn
            if (HasTextColor()) {
                plvcd->clrText=TextColor();
            }
            if (GetBrush()) {
                SelectObject(plvcd->nmcd.hdc, GetBrush());
                plvcd->clrTextBk=BackgroundColor();
            }

            // done - or could return CDRF_NOTIFYSUBITEMDRAW to handle those
            // via case CDDS_SUBITEM | CDDS_ITEMPREPAINT:
            return CDRF_NEWFONT;
        }
    }

    return CDRF_DODEFAULT;
}
user3161924
  • 1,849
  • 18
  • 33
  • 1
    ImageList is ancient and has GDI sensibilities. You'd use an icon instead of a bitmap if transparency is important. Hardly matters if you already figured out how to get the background color the same as the listview item color. – Hans Passant Sep 20 '21 at 19:27
  • Using icons is also better for DPI compatibility. Try `bitmap->GetHBITMAP(Gdiplus::Color::Transparent, &hbmp);` where `bitmap` is loaded directly from PNG file or resource. – Barmak Shemirani Sep 20 '21 at 19:53
  • I had found this article: https://stackoverflow.com/questions/632622/imagelist-transparency-on-listviews with an answer with 12 positive responses, and since the Gdiplus created bitmap should have a DIB and it was supposed to change the transparent colors to red, I wonder why it didn't work as that answer suggested. I still wonder if someone could explain the results I see? I did also try an .ico file but those were just white as well, even with `ILC_MASK` – user3161924 Sep 20 '21 at 20:18
  • Does this work with a regular listview control? How exactly you are adding to imagelist. – Barmak Shemirani Sep 20 '21 at 20:45
  • it's a regular listview using winapi, `ListView_SetImageList`. – user3161924 Sep 20 '21 at 20:52
  • Do you need alpha transparency or just simple keycolor transparency? – IInspectable Sep 20 '21 at 21:39
  • simple is good enough, but that's what I thought providing a color for GetHBITMAP was all about, it would set the transparent color to that color. But that doesn't work unless I loop through and set the alpha byte to 0 (see above where red shows). I'm trying to understand what exactly is going on and why. I found I can request `CDDS_ITEMPOSTPAINT` and `FillRect` with the background color and then draw the imageist manually using ILD_TRANSPARENT and it fills in that gap and background (but lose selection, would probably have to calculate it). Setting the imagelist bkcolor doesn't help. – user3161924 Sep 20 '21 at 22:43

0 Answers0