Unable to Set Overlay Image for CListCtrl - c++

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.

Related

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.

How to Place the image at specific location of the Picture Conrol in VC++

I m trying to overlay an image on a live video.The IDE used is Visual Studio Professional 2010. The code is developed in C++.When I try to overlay image on the live video, I m loading the image using a handle i.e.
HANDLE hBitmap;
hBitmap = LoadImage(NULL, L"C:\\Users\\User\\Documents\\Visual Studio 2010\\Projects\\BMP_Image.bmp",IMAGE_BITMAP, 0,0, LR_LOADFROMFILE );
I am using the mechanism of Alpha Blending to overlay the image on to the video. Problem I have encountered is, The image is overlayed five consecutive times on to the video .
I m passing the ID of a picture control, placed on the dialog box in the rc file, to load the live video and display it. I m not using any MFCs in the code. The video is rendered by using Direct 2D mechanism
The video resolution is 640*480 and bitmap image resolution is 128*128. If I take this bitmap , the video will produce five times of overlayed image on to the video..
I got the coordinates of dialog box using GetWindowRect() and ScreentoClient(). But I want the coordinates of the Picture control.
I have following doubts:
How to get the coordinates of the picture control???
How to place the image at specific location in a picture control???
Looking forward for ur positive response as earliest...
Regards,
Vivek
You can use the following function for retreiving the handle of your picture control:
::GetDlgItem( hWnd of your dialog, Id of your picture control)
By retreiving its handle, you can get to other info like its position, size and
::GetWindowRect(hWnd, &rc)
If you overlay the image through some API calls such as StretchBlt, you can place it anywhere you want.

Changing image bitmap or drawing bitmap on image causes image to disappear

I'm using two bitmaps to draw graphs on them. After drawing I need to show bitmap pictures in two Images. Assigning bitmap to Image or drawing bitmap to Image sometimes causes Image to disappear (you can see form background).
I have tried this:
Image->Picture->Bitmap->Assign(bitmap1);
Image2->Picture->Bitmap->Assign(bitmap2);
Image->Picture->Graphic = bitmap1;....
Image->Canvas->Draw(0,0,bitmap1);....
Image->Picture->Bitmap->Canvas->Draw(0,0,bitmap1);
If I don't have Sleep(100) between Image and Image2 redrawing, Image2 isn't visible for the most of the time. Also adding Image2->Refresh helps, but the issue still sometimes occurs to both Images.
If I save created bitmaps or Images to .jpeg files, all .jpeg images are correct and none of them are empty. Also Image->height, Image->picture->bitmap->height and width is always correct.
Can anyone tell me, what I'm doing wrong?
After a while I realised, that bitmaps and Images, which I saved, weren't all correct. If I was unable to see picture, it wasn't fully drawn. There were no errors, it occurred randomly, but I found out, that once program started to ignore my drawing commands, it didn't draw anything until the end of the function, which does drawing.
So - to check, if I can still draw, before assigning bitmap to Image, I did this:
Image3->Canvas->Pixels[y][0] = clRed;
TColor test = Image3->Canvas->Pixels[y][0];
Image3->Canvas->TextOut(y, 0, Device1->name);
TColor test2 = Image3->Canvas->Pixels[y][0];
if(test == test2)
{
imageUpdated = false;
delete Image3;
return;
}
Image->Picture->Graphic = Image3;
imageUpdated = true;
It means - I changed one pixel red, and after that printed over text, which should make that changed pixel white. Based on that I checked, if the color changed (was able to change pixel color and print text).
I really don't know reason, why it sometimes starts to ignore drawing commands, but I hope, that if someone runs into the same issue as I did, this answer might help him/her.

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.