MFC Image List Create ILC_COLORDDB Messing up Highlight - c++

In MFC, when I create an image list, using these flags:
m_ImageListThumb.Create(0x20, 0x20, ILC_COLORDDB | ILC_COLOR32, 0, 1);
m_ImageListThumb.Create(0x20, 0x20, ILC_COLOR32, 0, 1);
This ways shows correctly
I seem to need to use ILC_COLORDDB, otherwise sometimes highlighting an image with alpha won't show the highlighted blue at all. But my question is how to fix the blue overlay to be smooth, so it's not grainy, when using ILC_COLORDDB.
How do I fix this so ILC_COLORDDB gives a nice smooth blue highlight on click.

ILC_COLORDDB and ILC_COLOR32 are mutually exclusive, you can't use both flags. Look at their values:
#define ILC_COLORDDB 0x000000FE
#define ILC_COLOR32 0x00000020
If ILC_COLORDDB is specified the imagelist uses a bitmap created with CreateCompatibleBitmap that is compatible with the current display, so the results you get from this will vary with your current display settings.

Related

Unable to Set Overlay Image for CListCtrl

I'm trying to display images with overlays in a 'CListCtrl' within an MFC dialog box. The list control is in report/details mode.
I cannot find good documentation for showing overlays on some of my item images.
The code that is failing is shown below. I have a 64x32 bitmap with a folder icon in the first 32x32 pixels, and an overlay image in the second 32x32 pixels (IDB_FOLDERS32_OVERLAY). The bitmap has transparencies that seem to work fine.
CBitmap bm;
bm.LoadBitmap(IDB_FOLDERS32_OVERLAY);
m_ImageList.Create(32, 32, ILC_COLOR32, 2, 1);
int index = m_ImageList.Add(&bm, RGB(0, 0, 0));
ASSERT(index >= 0);
m_ImageList.SetOverlayImage(index, 2);
The last line returns 0, which indicates an error. GetLastError() returns 6 (ERROR_INVALID_HANDLE).
I can't for the life of me find reasonable documentation for how to do this anywhere on the web. Can anyone see what I'm missing?
Jonathan Potter was correct that I needed to include the ILC_MASK flag in order for SetOverlayImage() to returns a value that indicates success.
However, of all the documentation I could find online, nothing provided a complete description of how to do this. I didn't find a single source, for example, that showed what my bitmap should look like.
To make it more complicated, I am using ILC_COLOR32 to signify a 32-bit color bitmap with alpha (transparency) channel. So I don't have a mask and a mask does not appear compatible with alpha channels.
So in the end, I just created a bitmap with two images: The first is a folder, and the second is a folder with my overlay image on top of it. Problem solved.
At this point, it seems pointless to try and figure out if, or how, masks can be created with 32-bit alpha channel bitmaps.

MFC displaying png with transparent background

I need a way to display a PNG image with transparent background on a background with gradient color.
I have tried this:
CImage img;
CBitmap bmp;
img.Load(_T(".\\res\\foo.png"));
bmp.Attach(img.Detach());
CDC dcStatus;
dcStatus.CreateCompatibleDC(&dc);
dcStatus.SelectObject(&bmp);
dcStatus.SetBkColor(TRANSPARENT);
dc.BitBlt(rectText.left + 250, rectText.top, 14, 14, &dcStatus, 0, 0, SRCCOPY);
bmp.DeleteObject();
but foo.png gets black background wherever it is transparent in original image.
I did try to do a new bitmap that was painted with transparent color and did all possible operations on it, but that didn't help. Sample of one permutation:
CImage img;
CBitmap bmp;
img.Load(_T(".\\res\\foo.png"));
bmp.Attach(img.Detach());
CBitmap bmpMaska;
bmpMaska.CreateBitmap(14, 14, 1, 1, NULL);
CDC dcStatus;
dcStatus.CreateCompatibleDC(&dc);
dcStatus.SelectObject(&bmp);
CDC dcMaska;
dcMaska.CreateCompatibleDC(&dc);
dcMaska.SelectObject(&bmpMaska);
dcMaska.SetBkColor(dcStatus.GetPixel(0, 0));
//TODO: Bitmap ni transparent
dc.BitBlt(rectText.left + 250, rectText.top, 14, 14, &dcMaska, 0, 0, SRCCOPY);
dc.BitBlt(rectText.left + 250, rectText.top, 14, 14, &dcStatus, 0, 0, SRCAND);
bmp.DeleteObject();
bmpMaska.DeleteObject();
This did not do the trick. Either, there was all black square on the screen, or the result was the same as original.
I have also checked AlphaBlend API, but my code must be pure MFC + C++ witthout any additional APIs.
[Edit]: Company policy is as little APIs as possible. The code is supposed to run on embedded windows systems in real time.
[Edit 2]: I am not bound to PNG image format, meaning, anything that will display as transparent, goes.
Please, tell me what am I doing wrong?
Convert the png to a 32 bit bmp file. Google 'AlphaConv' and use that. PNG's are a PITA to work with - several API's claim to support them but actually don't, or only partially, or only on some platforms etc.
Load your 32-bit bmp using CBitmap::LoadBitmap (from resources - this is by far the easiest)
Then use CDC::AlphaBlend() to draw your bitmap. TransparentBlt() doesn't work with an alpha channel - it's just either draw the pixel or not. AlphaBlend is part of the win32 API, and you could still investigate CImage::AlphaBlend if you'd like, but that has a bug somewhere (I forgot what exactly) so I always use the raw ::AlphaBlend.
But beware - you need to premultipy the alpha channel for correct display. See my answer on How to draw 32-bit alpha channel bitmaps? .
No variation of what you described will work. You need another API to get this to work. Or, you could use GetDIBits and do your own version of ::AlphaBlend() :)
Based on what you're asking for (simply some set of pixels being transparent) it's probably easiest to use a 24- or 32-bit BMP, and simply pick a color to treat as transparent. Pre-process your picture to take any pixel that precisely matches your transparent color and increase change the least significant bit of one of the channels.
Given 8 bits per channel, this won't normally cause a visible change. Then draw the pixels you want transparent in one exact color. This is easy to do in something like a paint program.
You can then draw that to your DC using TransparentBlt. That lets you specify the color you want to treat as transparent.

Why am I getting black background when displaying a list-view icon?

I'm not sure why I'm getting this black outline when I add an icon to the CListCtrl (or list-view control)?
I load it as such:
//HICON hIcon;
LoadIconWithScaleDown(theApp.m_hInstance, MAKEINTRESOURCE(Icon_ID), 15, 15, &hIcon);
I then create my image list as such:
//CImageList iml;
iml.Create(15, 15, ILC_COLOR32, numberIcons, 0);
iml.Add(hIcon);
the list view is prepped first:
//CListCtrl lst;
lst.SetExtendedStyle(LVS_EX_DOUBLEBUFFER | LVS_EX_FULLROWSELECT |
LVS_EX_LABELTIP | LVS_EX_HEADERDRAGDROP | LVS_EX_SUBITEMIMAGES);
lst.ModifyStyle(0, LVS_SHOWSELALWAYS);
and the icon is displayed in the subitem of the list as such:
int nInd = lst.InsertItem(c, L"Main label");
lst.SetItem(nInd, nSubitemIndex, LVIF_TEXT | LVIF_IMAGE, L"2 files", nIconInd, 0, 0, 0);
So what am I doing wrong?
PS. I ran this test on my Windows 8.1 with a 32-bit trucolor display setting.
The icon itself though is a 256-color image since I don't see any reason to waste space on a 32-bit icon with an alpha channel for such a small size & simple design:
LVS_EX_FULLROWSELECT has transparency issues on XP, you are likely encountering that. You may have to owner-draw the images onto the list view to preserve the transparency. Or, load the images into one image list, then render a copy of the images with a background color matching the list view's color to a separate image list, and then use the second image list with the list view.
Maybe water under the bridge by now, but I found colordepth settings of 8 bit on my offending imagelist. Setting it to 32 resulted in transpareency working as expected...
Check this thread here
Getting alpha blending to work with CImageList
Adding this line one C++ file did the trick:
enter code here
#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
Do not even ask... but it took me a long time to find that out

Why would GDI+ colours vary based off whether a tooltip is visible?

I'm displaying a bitmap using GDI+. After loading the bitmap from a DLL resource I set the background colour (blue - #0000FF) to transparent using TransparentBlt. On Windows Vista and later this works as expected.
However, on a Windows XP system we're testing on this only works when any tooltip (e.g. the "title" property in IE, or Windows Explorer's tooltip shown when hovering the mouse over a file, etc) is displayed. The rest of the time the background colour is still blue.
Has anyone encountered this before, or know of a way to stop this occurring and for the blue to be properly made transparent?
Edit: After further investigation I found that setting colour depth in Windows XP to 16 bit colours instead of 32 bit colours caused TransparentBlt to start working normally again. Obviously this isn't an ideal solution, specifying what colour depth must be used, but does this give any hint to what might be happening?
Edit2: Code sample included.
m_pGDIBitmap = new Gdiplus::Bitmap(_Module.m_hInst, MAKEINTRESOURCE(lImageResource));
m_hMemDC = CreateCompatibleDC(hdc);
Gdiplus::Graphics myGraphics(m_hMemDC);
myGraphics.DrawImage(m_pGDIBitmap,
Gdiplus::Rect(0, 0, m_pGDIBitmap->GetWidth(), m_pGDIBitmap->GetHeight()),
0,
0,
m_pGDIBitmap->GetWidth(),
m_pGDIBitmap->GetHeight(),
Gdiplus::UnitPixel, &imAtt);
SetStretchBltMode(hdc, HALFTONE);
SetBrushOrgEx(hdc, rcBounds.left, rcBounds.top, NULL);
TransparentBlt(hdc, rcBounds.left, rcBounds.top, iScaledWidth, iScaledHeight, m_hMemDC, 0, 0, iBitmapWidth, iBitmapHeight, GetPixel(m_hMemDC, 0, 0));
You must show some sample code - the code that loads the bitmap and the code that blits it to display.
From the symptoms that you describe, my guess is that you load the bitmap not in its native format, but in the current display format. This means, that when the bit depth of the bitmap differs from the bit depth of the display, an automatic color space conversion is made. When this happens, the color that you provide to TransparentBlt is actually different from the color in the bitmap.
Possible alternative solutions:
Make sure that the bitmap is loaded in its native format without conversion.
Allow the conversion to take place, but instead of providing a hardcoded color value to TransparentBlt, make a GetPixel of a known "transparent" pixel of the bitmap (like top-left), and provide this value to the TransparentBlt.
What I ended up doing was more of a workaround, but it did work. I changed the background colour to black and added the following code before the DrawImage call:
Gdiplus::ImageAttributes imAtt;
imAtt.SetColorKey(Gdiplus::Color(0, 0, 0), Gdiplus::Color(0, 0, 0), Gdiplus::ColorAdjustTypeBitmap);
For some reason using this with blue as the background didn't work and using TransparentBlt on its own with either colour didn't work, but the combination applied the transparency correctly on the various OSes and colour depths that I tried.
If I had access to a paint program that supported bitmap files with an alpha channel, i.e. 32 bit bitmaps, I suspect making the background explicitly transparent and then using AlphaBlend would have worked as well but I didn't have the ability to try that at the time.

Adding a transparent bitmap to a windows button

It's a while since I've done this, but I'm trying to add a custom button graphic to a windows button, with some transparent areas. I've tried various schemes but can't seem to get the transparent areas to show. Here's my code:
hbmpUpDisabled = LoadImage(instance,MAKEINTRESOURCE(IDB_UPARROWDISABLED), IMAGE_BITMAP, 0, 0, LR_DEFAULTSIZE | LR_LOADTRANSPARENT | LR_LOADMAP3DCOLORS );
SendMessage(GetDlgItem(hWndDlg, IDC_MOVEUP),BM_SETIMAGE,(WPARAM)IMAGE_BITMAP,(LPARAM)hbmpUpDisabled);
Does anyone notice any problems here? It works if my bitmap is a 1-bit bitmap. I couldn't get a 32 bit bitmap to work, and I'm not sure how to setup a 24 bit or 8 bit bitmap to do it.... I tried a custom 255,0,255 color (which IIRC is a default transparent value), but so far no joy....
LR_LOADMAP3DCOLORS should map grey - in the source image - to to the current button face color. Buttons do not use AlphaBlt or TransparentBlt so there is no way to actually (short of custom painting) set a bitmap with transparent or alpha'd areas onto a button and expect it to work. You just have to pre-prepare the bitmap with the correct button color in its background areas.
That said - I suspect that some of these restrictions may be lifted for buttons implemented by common controls v6. Add commctl 6 as a dependend assembly to your exe and see if the behaviour changes.