Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

ImageList_Draw and icons with alpha channel

1,053 views
Skip to first unread message

Timo Kunze

unread,
Oct 24, 2005, 3:50:33 PM10/24/05
to
Hi,

I'm creating a memory DC which is compatible to the desktop's DC. I set
the background color to GetSysColor(COLOR_HIGHLIGHT) and the text color
to GetSysColor(COLOR_HIGHLIGHTTEXT). Then I create a bitmap, select it
into the memory DC, fill it with COLOR_WINDOW and select a valid font
into the DC.
The next thing I do is draw an icon into that DC using ImageList_Draw()
with ILD_NORMAL. The imagelist was created with ILC_COLOR32 and ILC_MASK
and contains 32bpp icons (i. e. they have an alpha channel). Afterwards
I fill a rectangle next to the drawn icon with COLOR_HIGHLIGHT and draw
a text into that rectangle using DrawText() with DT_EDITCONTROL,
DT_NOPREFIX, DT_SINGLELINE, DT_VCENTER and DT_END_ELLIPSIS.
Last but not least I create another imagelist with ILC_COLOR32 and
ILC_MASK and add the bitmap I just drew to that imagelist.

Now here's my problem:
I draw the bitmap to a window's DC using ImageList_Draw() with
ILD_NORMAL. On Windows XP, the icon is drawn together with the text -
just as expected. But on Windows 2003 the icon is drawn and the text is
missing. This only happens if the icon has an alpha channel.
Why does this happen and how can I fix it?

Note: DrawText() does NOT fail.

Thanks in advance
Timo

P.S.: I posted this to microsoft.public.win32.programmer.ui earlier, but
this group probably suits more.
--
www.TimoSoft-Software.de - the home of ExplorerTreeView
Stop software patents!

jk...@prodoc.com

unread,
Oct 24, 2005, 4:24:06 PM10/24/05
to
Any chance the text color = the background color so the text is
invisible?
Jim Kane

Timo Kunze

unread,
Oct 24, 2005, 7:01:20 PM10/24/05
to
jk...@prodoc.com schrieb:

> Any chance the text color = the background color so the text is
> invisible?
No. I've created a small sample:
www.timosoft-software.de/stuff/AlphaIcons.zip

To my surprise this sample shows the error not only on Windows 2003 SP1,
but also on Windows XP SP2.

Some words about the sample:
The icon loading code is a big mess, but it works. I couldn't convince
LoadImage to load 32bpp icons without loosing the alpha channel and the
solution with FindResource was the first one I got working. I also
couldn't convince Visual C++ to compile the 32 bpp icon into the app
without loosing the alpha channel. So I compile, open ResHacker and
replace the dummy icon with an icon out of shell32.dll (icon group #512
on German WinXP SP2).
As you can see, the sample creates a 32bpp imagelist and inserts 2
icons: a 32bpp with alpha-channel data and a 8bpp.
In OnPaint() I draw 3 pictures of each icon together with some text. The
left column uses the 32bpp icon, the right one the 8bpp. In the first
row I draw the icon and the text directly to the target DC. In the 2nd
row I draw to a memory DC and then the result to the target DC. In the
3rd row I draw to a memory DC, insert the result into a new imagelist
and call ImageList_Draw to draw into the target DC.
On my system the text is missing on the left column, 3rd row.

Timo

Michael Phillips, Jr.

unread,
Oct 25, 2005, 11:13:08 AM10/25/05
to
>The imagelist was created with ILC_COLOR32 and ILC_MASK

This requires two bitmaps, an XOR mask and an AND mask.
Your code adds one bitmap.

Why don't you take the HICON and split out the masks.

Use GetIconInfo to obtain a DDB XOR mask and the AND mask.

Then add them to the image list created with the flags ILC_COLORDDB |
ILC_MASK.

"Timo Kunze" <TKunz...@gmx.de> wrote in message
news:ukN4zQN2...@TK2MSFTNGP09.phx.gbl...

Timo Kunze

unread,
Oct 25, 2005, 11:55:41 AM10/25/05
to
Okay, I see, but shouldn't it work if I remove ILC_MASK from the
imagelist that I add the bitmap to? I just tried it and it doesn't make
any difference.
But I'll test your suggestion of splitting out the mask.

Thanks
Timo

Michael Phillips, Jr.

unread,
Oct 25, 2005, 12:50:53 PM10/25/05
to
>Okay, I see, but shouldn't it work if I remove ILC_MASK from the
> imagelist that I add the bitmap to?

Yes it works on my machine (XPSP2)
See your code below:
// add the bitmap to a new imagelist and draw it to the dialog
WTL::CImageList iml;
iml.Create(90, 32, ILC_COLORDDB, 1, 0); // <----I removed the ILC_COLOR32 |
ILC_MASK flags
iml.Add(hBMP);
DeleteObject(hBMP);
iml.Draw(ps.hdc, 0, 10, 90, ILD_NORMAL);
iml.Destroy();


"Timo Kunze" <TKunz...@gmx.de> wrote in message

news:%23LZTZyX...@TK2MSFTNGP15.phx.gbl...

Timo Kunze

unread,
Oct 25, 2005, 9:32:23 PM10/25/05
to
I still have problems to use the code in my app. Here is the simplified
code:

HDC hCompatibleDC = ::GetDC(NULL);
HDC hMemoryDC = ::CreateCompatibleDC(hCompatibleDC);
HBITMAP hDragImage = ::CreateCompatibleBitmap(hCompatibleDC, 100, 50);
HBITMAP hPreviousBitmap = (HBITMAP) ::SelectObject(hMemoryDC, hDragImage);
RECT rc = {0};
rc.right = 100;
rc.bottom = 50;
::FillRect(hMemoryDC, &rc, (HBRUSH) ::GetStockObject(WHITE_BRUSH));
::SetBkColor(hMemoryDC, ::GetSysColor(COLOR_HIGHLIGHT));
::SetTextColor(hMemoryDC, ::GetSysColor(COLOR_HIGHLIGHTTEXT));
HFONT hPreviousFont = (HFONT) ::SelectObject(hMemoryDC, hFont);

HDC hMaskMemoryDC = ::CreateCompatibleDC(hCompatibleDC);
HBITMAP hDragImageMask = ::CreateBitmap(100, 50, 1, 1, NULL);
HBITMAP hPreviousBitmapMask = (HBITMAP) ::SelectObject(hMaskMemoryDC,
hDragImageMask);
::FillRect(hMaskMemoryDC, &rc, (HBRUSH) ::GetStockObject(WHITE_BRUSH));

::ImageList_Draw(hSourceImageList, 8, hMemoryDC, 1, 1, ILD_NORMAL);
::ImageList_Draw(hSourceImageList, 8, hMaskMemoryDC, 1, 1, ILD_MASK);
rc.left = 50;
rc.top = 10;
rc.right = 100;
rc.bottom = 30;
::FillRect(hMemoryDC, &rc, ::GetSysColorBrush(COLOR_HIGHLIGHT));
::FillRect(hMaskMemoryDC, &rc, (HBRUSH) ::GetStockObject(BLACK_BRUSH));
::DrawText(hMemoryDC, _T("Hello"), 5, &rc, DT_SINGLELINE | DT_VCENTER |
DT_END_ELLIPSIS);

::SelectObject(hMemoryDC, hPreviousBitmap);
::SelectObject(hMaskMemoryDC, hPreviousBitmapMask);
::SelectObject(hMemoryDC, hPreviousFont);

HIMAGELIST hDragImageList = ::ImageList_Create(100, 50, ILC_COLORDDB |
ILC_MASK, 1, 0);
::ImageList_Add(hDragImageList, hDragImage, hDragImageMask);

::DeleteObject(hDragImage);
::DeleteObject(hDragImageMask);
::DeleteDC(hMemoryDC);
::DeleteDC(hMaskMemoryDC);
::ReleaseDC(NULL, hCompatibleDC);
return (LRESULT) hDragImageList;

hDragImageList will be used with ::ImageList_BeginDrag to visualize a
drag'n'drop operation.

The problems I have are:
1) On Windows XP, pixels with alpha transparency are not transparent.
Instead they're drawn in the color that I fill hMemoryDC with in the
beginning. On Windows 2003, alpha transparency is wrong if the drag
image is drawn with ImageList_Draw, but it is correct during drag'n'drop
(obviously ImageList_BeginDrag does some magic).
2) On Windows 2003, the text's background is a translucent white instead
of blue. The text itself is in solid white as expected. I've already
checked the system colors, but they are the same as on my Windows XP
system on which the text's background has the correct color.
3) If I use ILC_COLOR32 instead of ILC_COLORDDB, alpha transparency is
correct, but the text is completely missing.

Does anyone see what I'm doing wrong? I don't.

Michael Phillips, Jr.

unread,
Oct 26, 2005, 11:19:20 AM10/26/05
to
I tried my suggestion with your code and it works for me.

Here are the changes that I made to demonstrate my suggestion:

... // other code

HRSRC hResource = ::FindResource(_Module.GetResourceInstance(),
MAKEINTRESOURCE(10), RT_ICON); // 32bpp
if(hResource) {
HGLOBAL hMem = ::LoadResource(_Module.GetResourceInstance(), hResource);
if(hMem) {
LPVOID pIconData = ::LockResource(hMem);
if(pIconData) {
HICON hIcon = ::CreateIconFromResourceEx((PBYTE) pIconData,
::SizeofResource(_Module.GetResourceInstance(), hResource), TRUE,
0x00030000, 0, 0, LR_DEFAULTCOLOR);
if(hIcon) {
largeImageList.AddIcon(hIcon);
ICONINFO iconInfo;
// break out the image masks
GetIconInfo(hIcon, &iconInfo);
m_h32bppXORMask = iconInfo.hbmColor;
m_h32bppANDMask = iconInfo.hbmMask;
}
}
}
}

... // other code

// add the 32bpp Alpha Icon Bitmap Masks to a new imagelist and draw it to

the dialog
WTL::CImageList iml;

iml.Create(32, 32, ILC_COLOR32 | ILC_MASK, 2, 0);
iml.Add(m_h32bppXORMask);
iml.Add(m_h32bppANDMask);
DeleteObject(m_h32bppXORMask);
DeleteObject(m_h32bppANDMask);
iml.SetBkColor(GetSysColor(COLOR_3DFACE));


iml.Draw(ps.hdc, 0, 10, 90, ILD_NORMAL);
iml.Destroy();

// Draw the captioned text next to the rendered imagelist bitmaps
SetBkColor(hDC, GetSysColor(COLOR_HIGHLIGHT));
SetTextColor(hDC, GetSysColor(COLOR_HIGHLIGHTTEXT));
rc.left = 50;
rc.top = 190;
rc.right = 90;
rc.bottom = 20;
DrawText(ps.hdc, _T("Hello"), 5, &rc, DT_EDITCONTROL | DT_NOPREFIX |
DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS);

"Timo Kunze" <TKunz...@gmx.de> wrote in message

news:ujTuP0c2...@tk2msftngp13.phx.gbl...

Timo Kunze

unread,
Oct 26, 2005, 2:05:40 PM10/26/05
to
You draw the icon to the dialog and then the text next to it. This works
for me, too. But I need an imagelist that contains the icon with the
text next to it, i. e. I need icon and text within the same bitmap. This
imagelist will be used with ImageList_BeginDrag and the other
drag'n'drop functions.
So I create a XOR mask and an AND mask as you suggested. I've ensured
that the rectangle, that contains the text in the XOR mask, is all black
in the AND mask, so it won't be transparent in the combined picture.

If I create an imagelist with ILC_COLORDDB | ILC_MASK and add the image
(i. e. both masks) which contains icon AND text, the drag image indeed
contains icon and text, BUT:
- Pixels that have an alpha transparency in the source icon are not
transparent anymore.
- On Windows 2003 the alpha transparency seems to be correct, but the
text is wrong. The text's background isn't blue as it should (and as it
is on XP), but white. I've absolutely no idea why this happens.

If I create an imagelist with ILC_COLOR32 | ILC_MASK and add the image
(i. e. both masks) which contains icon AND text, alpha transparency
seems to be correct, but the drag image contains the icon only.
Could this have something to do with the palette? Or do I have to create
the bitmap, that I'm adding, with CreateDIBSection()?

Here're 3 screenshots of how the drag image looks if the imagelist was
created with ILC_COLORDDB | ILC_MASK:
1) Windows XP SP2 - drag image is correct, except that alpha
transparency is lost.
www.timosoft-software.de/stuff/WinXP.png
2) Windows 2003 SP1 - alpha transpareny is correct, but the text's
background is white instead of blue (the ImageList_BeginDrag function
makes the drag image semi-transparent, so the blue titlebar shines
through and makes the text background light-blue).
www.timosoft-software.de/stuff/Win2k3.png
3) Windows 2003 SP1 - OLE drag'n'drop, which displays my drag image
using IDragSourceHelper and IDropTargetHelper, displays the text
background correctly, but alpha-transparency is lost (you can't see this
on the screenshot).
www.timosoft-software.de/stuff/Win2k3OLE.png

The box to the right of the listview displays the drag image and its
mask as they are added to the imagelist.

BTW, I think it's wrong how you're adding the mask to the imagelist. You
call ImageList_Add() once for each image (image = XOR mask + AND mask).
If you want to specify a custom AND mask, you can do this using the 3rd
parameter of ImageList_Add().

Michael Phillips, Jr.

unread,
Oct 26, 2005, 3:11:59 PM10/26/05
to
There are several CImageList Add methods.

The one that I think will work best for you is
Add(HICON hIcon).

Here is what I did:

1) Load the icons as you describe in your code
2) Create a Memory DC and DIBSECTION bitmap
for each bitdepth. You will need a Palette for 8bpp or less bitmaps.
3) Select the Dib into the device context
4) Use DrawIcon to draw the icon to the memory device
5) Use DrawText as in your code to draw the text next to the icon.
6) After you use SelectObject and DeleteDC, you now have a
bitmap with the icon and captioned text next to it.
7) You now need to create the XOR and AND masks from this DIB
For the XOR mask use CreateCompatibleBitmap (i.e., create another
DIBSECTION)
For the AND mask use CreateBitmap
Create memory DC's for each and select the bitmaps into the DC's

Use SetDIBColorTable for 8bpp or less bitmaps before creating the masks
to make sure the destination XOR bitmap has a color table.

Here is my code for the masks:

// Create AND and XOR masks
for ( DWORD x = 0; x < dwWidth; x++ )
{
for ( DWORD y = 0; y < dwHeight; y++ )
{
// clrTransparent is a COLORREF for the transparent color
// You could sample using GetPixel
if ( ::GetPixel( hSrcImageDC, x ,y ) == clrTransparent ) // Src Bitmap
from above
{
::SetPixel( hAndMaskDC, x, y, RGB(255, 255, 255) );
::SetPixelV( hXorMaskDC, x, y, RGB(0,0,0) );
}
else
{
::SetPixel( hAndMaskDC, x, y, RGB(0,0,0) );
::SetPixel( hXorMaskDC, x, y, ::GetPixel( hSrcImageDC, x ,y ) );
}
}
}
::GdiFlush();

8) Now that you have the masks you need to create an Icon
using CreateIconIndirect
9) Add the icons to your image list with Add(HICON hIcon).

Converting the DIB format for each bitdepth is easy. I use BitBlt
to do all of the work.

Because your sample Icon has shadows, I found that using the 8bpp
icon as the source gave the best results. You may need to fixup
the icon first to eliminate the artifacts produced by the Mask creation.


"Timo Kunze" <TKunz...@gmx.de> wrote in message

news:%230nUofl...@TK2MSFTNGP15.phx.gbl...

Michael Phillips, Jr.

unread,
Oct 26, 2005, 5:40:17 PM10/26/05
to
You were correct. I need to use
CImageList::Add(m_h32bppXORMask,m_h32bppANDMask);

As In:


// add the 32bpp Alpha Icon Bitmap Masks to a new imagelist and draw it to
the dialog
WTL::CImageList iml;

iml.Create(90, 32, ILC_COLOR32 | ILC_MASK, 2, 0); // Explorer icon with
highlighted "Hello" text next to the icon
iml.Add(m_h32bppXORMask,m_h32bppANDMask); // This is the icon that I
created with my previous post
DeleteObject(m_h32bppXORMask);
DeleteObject(m_h32bppANDMask);
iml.SetBkColor(CLR_NONE);
SetBkColor(ps.hdc, GetSysColor(COLOR_3DFACE));


iml.Draw(ps.hdc, 0, 10, 90, ILD_NORMAL);
iml.Destroy();

The image displays correctly with XPSP2 and Windows 2003SP1

"Michael Phillips, Jr." <mphil...@nospam.jun0.c0m> wrote in message
news:OlfocEm2...@tk2msftngp13.phx.gbl...

Timo Kunze

unread,
Oct 26, 2005, 7:37:59 PM10/26/05
to
We're getting closer. :)
With my (better: your) current code, the drag image contains the icon
and the text (with correct colors) - on Windows XP SP2 as well as on
Windows 2003 SP1. This is the first time I got this working with
ILC_COLOR32. Looks like using CreateDIBSection is the key.
However, the per-pixel alpha transparency still gets lost. I think it's
because the AND mask tells GDI that these pixels are opaque and actually
it should tell GDI that they're transparent, am I right? Then we'd need
a way to read out each pixel's alpha channel in the for loops and set
the AND mask's pixel to white if it is different than 255. Shouldn't be
that difficult, but I'm too tired to try it right now.

Here's the code I'm currently using:

// create a memory DC
WTL::CDC memoryDC;
memoryDC.CreateCompatibleDC();

// create a 32bpp DIB
WTL::CBitmap dibBitmap32bpp;
BITMAPINFO bitmapInfo = {0};
bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitmapInfo.bmiHeader.biWidth = 90;
bitmapInfo.bmiHeader.biHeight = 50;
bitmapInfo.bmiHeader.biPlanes = 1;
bitmapInfo.bmiHeader.biBitCount = 32;
bitmapInfo.bmiHeader.biCompression = BI_RGB;
dibBitmap32bpp.CreateDIBSection(memoryDC, &bitmapInfo, DIB_RGB_COLORS,
NULL, NULL, 0);

// setup the memory DC
WTL::CFontHandle font = (HFONT) SendMessage(WM_GETFONT, 0, 0);
HFONT hPreviousFont = NULL;
if(!font.IsNull()) {
hPreviousFont = memoryDC.SelectFont(font);
}
HBITMAP hPreviousBitmap1 = memoryDC.SelectBitmap(dibBitmap32bpp);
memoryDC.SetBkColor(::GetSysColor(COLOR_HIGHLIGHT));
memoryDC.SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT));

/* Fill the bitmap's background with an ugly magenta. Magenta pixels
will become transparent. */
COLORREF transparentColor = RGB(255, 0, 255);
WTL::CBrush backgroundBrush;
backgroundBrush.CreateSolidBrush(transparentColor);
memoryDC.FillRect(WTL::CRect(0, 0, 90, 50), backgroundBrush);

// draw content
HICON hIcon = ::ImageList_ExtractIcon(NULL, hSourceImageList, item.iImage);
memoryDC.DrawIcon(0, 0, hIcon);
::DestroyIcon(hIcon);
memoryDC.DrawText(_T("Hello"), 5, WTL::CRect(40, 10, 80, 30),
DT_SINGLELINE | DT_VCENTER | DT_END_ELLIPSIS);

// create the masks that together build the drag image
WTL::CBitmap xorMask;
xorMask.CreateCompatibleBitmap(memoryDC, 90, 50);
WTL::CDC xorMaskDC;
xorMaskDC.CreateCompatibleDC();
HBITMAP hPreviousBitmap2 = xorMaskDC.SelectBitmap(xorMask);

WTL::CBitmap andMask;
andMask.CreateBitmap(90, 50, 1, 1, NULL);
WTL::CDC andMaskDC;
andMaskDC.CreateCompatibleDC();
HBITMAP hPreviousBitmap3 = andMaskDC.SelectBitmap(andMask);

// draw the masks pixel by pixel
for(DWORD x = 0; x < 90; x++) {
for(DWORD y = 0; y < 50; y++) {
if(memoryDC.GetPixel(x, y) == transparentColor) {
andMaskDC.SetPixel(x, y, RGB(255, 255, 255));
xorMaskDC.SetPixelV(x, y, RGB(0, 0, 0));
} else {
andMaskDC.SetPixel(x, y, RGB(0, 0, 0));
xorMaskDC.SetPixel(x, y, memoryDC.GetPixel(x, y));
}
}
}
::GdiFlush();

// clean up
memoryDC.SelectFont(hPreviousFont);
memoryDC.SelectBitmap(hPreviousBitmap1);
xorMaskDC.SelectBitmap(hPreviousBitmap2);
andMaskDC.SelectBitmap(hPreviousBitmap3);

// create the imagelist containing our drag image
HIMAGELIST hDragImageList = ::ImageList_Create(90, 50, ILC_COLOR32 |
ILC_MASK, 1, 0);
::ImageList_SetBkColor(hDragImageList, CLR_NONE);
// add the drag image
::ImageList_Add(hDragImageList, xorMask, andMask);

// ImageList_BeginDrag will be called with hDragImageList

Michael Phillips, Jr.

unread,
Oct 27, 2005, 10:11:31 AM10/27/05
to
The AND mask represents the "Alpha Channel".

Where the pixel is marked as "White", the pixel in the final
destination bitmap will be replaced by the background color
after application of the XOR and AND masks.

Using masks works for all bit depths and allows you to
create icons, cursors or use bitmaps that can be TransBlt
accross the screen. You don't have the option of fine
tuning the alpha channel for degree of opacity on a per
pixel basis.

If you want to define the degree of opacity
on a per pixel basis, you only have one option.

For the 32bpp case only, you may create the masks as follows:
1) Use a BITMAPV5HEADER and CreateDIBSection
to create an alpha channel canvas to draw your icon and text.
2) Use CreateBitmap to create an AND mask. You leave this
mask alone(i.e., don't set the bits on or off )
3) Use the pointer to the DIBSECTION bits to create the "AND"
mask. You use the same algorithm but operate on the alpha
channel only. You can refine the degree of opacity from 0 to 255
on a per pixel basis.
4) When your done, premultiply the alpha channel against the individual
colors.
5) Use the rest of your code to add the bitmap masks.

Keep in mind that normal Windows bitmaps are BI_RGB where
each pixel is formatted as 0x00BBGGRR. The alpha channel is
ignored.

An Alpha channel bitmap created by a BITMAPV5HEADER is
formatted as 0xAARRGGBB. If you premultiply the alpha channel
against the individual colors, you can ensure yourself that the
alpha channel will be preserved using Windows GDI calls.


"Timo Kunze" <TKunz...@gmx.de> wrote in message

news:%235CZSZo...@TK2MSFTNGP12.phx.gbl...

Timo Kunze

unread,
Oct 28, 2005, 9:36:23 AM10/28/05
to
I've just found out (more or less by accident) why text was missing if
ILC_COLOR32 was used: Functions like DrawText and FillRect set the alpha
channel of the pixels they draw to 0, which means 100% transparent. IMHO
this should be documented explicitly.
So what I'm doing now is draw the whole stuff like I posted on October
26th at 03:32 AM and post-process it using GetDIBits/SetDIBits to change
the text-area's alpha channel to 255.

Many thanks for your help.

Michael Phillips, Jr.

unread,
Oct 28, 2005, 9:53:39 AM10/28/05
to
> Functions like DrawText and FillRect set the alpha
> channel of the pixels they draw to 0, which means 100% transparent.

Timo,

This may be one of those "By Design" gotchas!

The BI_RGB pixel format is 0x00BBGGRR. It would
seem that DrawText, FillRect and other GDI functions
would adhere to writing their pixels in this format.

I am glad you are making progress!

"Timo Kunze" <TKunz...@gmx.de> wrote in message

news:eZGwUS82...@tk2msftngp13.phx.gbl...

Timo Kunze

unread,
Oct 28, 2005, 1:58:00 PM10/28/05
to
There's a new problem:
If ILC_COLOR32 isn't supported anyway (e. g. if comctl32.dll 5.x is
used), I fall back to much simpler code which works fine for icons
without alpha channel.
Now imagine ILC_COLOR32 is supported, but the icon does not have an
alpha channel. In this case ImageList_Draw() sets each pixel's alpha
channel to 0, so the icon becomes invisible. My first idea was to check
the icon's color depth and fall back to the simpler code if it is less
than 32bpp. But since the imagelist, that I take the icon from, was
created with ILC_COLOR32, the icon's color depth is reported to be 32bpp.
So I need a way to distinguish between 32bpp icons with alpha channel
and 32bpp icons without alpha channel. The only solution I can think of
is search for a pixel with an alpha channel greater than 0 and change
all pixels' alpha channel to 255 if none was found.
As long as I'm generating the drag image for only 1 item, this would be
acceptable, but I'm concerning about performance for the cases where the
drag image is generated for 30 or more items...

Why wasn't the alpha channel designed that way, that 255 means invisible
and 0 means opaque? IMHO it would have been much better for compatibility.

Michael Phillips, Jr.

unread,
Oct 29, 2005, 10:33:36 AM10/29/05
to
For a 32bpp Icon, GDI will report it as BI_RGB.

If the icon had an alpha channel, GDI should report it
as BI_BITFIELDS. Unfortunately, it doesn't report
alpha channel bitmaps with GetObject and DIBSECTION!

Since the formats are different (i.e, 0x00BBGGRR vs 0xAARRGGBB),
I am not sure that GDI converts the alpha channel format internally to
BI_RGB by premultiplying the alpha channel or
that it sets a structure variable in the GDI Object table for bitmaps!

Clearly GDI is able to create Alpha Channel Cursors and Icons and the
AlphaBlend function can figure it out when the DIBSection is selected
into a Device Context! It would be nice if Microsoft published some
easy method of figuring it out!

I lean to GDI premultiplying the alpha channel and converting the format
from BI_BITFIELDS to BI_RGB.

None of this helps you to figure out whether or not
the icon was an alpha channel icon or one produced by two masks.

You could use GetPixel to test position(0,0) and/or position(1,1) of the AND
mask to see if it returns 255 or 0 (i.e., transparent vs. opaque for the
destination pixel).

If the AND mask was set, then you have a BI_RGB 32bpp icon.

For a 32bpp icon with an alpha channel, the AND mask is not touched.
It is redundant!

Creating DC's and selecting the AND mask in an out to sample
pixels may be a performance bottleneck. You could always
write your own GetPixel to sample the raw bits instead.
Use GetObject to return the pointer to the bits.

For a 1bpp AND mask, the color is indexed 8 pixels per byte.
The raw bit sampling should be quick.


"Timo Kunze" <TKunz...@gmx.de> wrote in message

news:%23xznnk%232FH...@TK2MSFTNGP12.phx.gbl...

Timo Kunze

unread,
Oct 30, 2005, 1:58:59 PM10/30/05
to
*lol* After I've implemented some bloated code which decides whether an
icon uses the alpha channel, I've found the undocumented ILIF_ALPHA
flag, which can be used with IImageList::GetItemFlags() to do exactly
this...
Sometimes Microsoft drives me nuts...

Gary Chanson

unread,
Oct 30, 2005, 3:31:43 PM10/30/05
to

"Timo Kunze" <TKunz...@gmx.de> wrote in message
news:uLk95PY3...@TK2MSFTNGP09.phx.gbl...

> *lol* After I've implemented some bloated code which decides whether an
> icon uses the alpha channel, I've found the undocumented ILIF_ALPHA
> flag, which can be used with IImageList::GetItemFlags() to do exactly
> this...
> Sometimes Microsoft drives me nuts...

Only sometimes? ;)

--
-GJC [MS Windows SDK MVP]
-Software Consultant (Embedded systems and Real Time Controls)
- http://www.mvps.org/ArcaneIncantations/consulting.htm
-gcha...@mvps.org

Michael Phillips, Jr.

unread,
Oct 31, 2005, 11:59:36 AM10/31/05
to
Actually, it is documented here:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/shellcc/platform/commctls/imagelist/structures/imageinfo.asp

The IImageList interface implements the GetItemFlags method
which returns the ILIF_ALPHA flag upon reading the IMAGELISTSTATEFLAGS!

I am not clear how the ImageList determines this from the Icon Masks.

Does anyone know how the ImageList sets the State Flags for the alpha
channel?

"Timo Kunze" <TKunz...@gmx.de> wrote in message

news:uLk95PY3...@TK2MSFTNGP09.phx.gbl...

Timo Kunze

unread,
Oct 31, 2005, 12:28:29 PM10/31/05
to
Hi Michael,

Michael Phillips, Jr. schrieb:

does your browser display other content than mine? I can't find
ILIF_ALPHA neither in that article nor anywhere else in MSDN. It's
mentioned in commoncontrols.idl, that's all.

Michael Phillips, Jr.

unread,
Oct 31, 2005, 12:57:02 PM10/31/05
to
> It's mentioned in commoncontrols.idl, that's all.

That is where it is mentioned but the IImageList is an interface
that is based on the ImageList from the Common Controls Library as
documented in that link.

Commoncontrols.idl provides its own documentation in the .idl format which
can be read.
It is sparse but you can write code based on the information provided by the
Commoncontrols.idl alone!

The flag seems to be valid only in version 6 of the Comctl32.dll.
This makes sense since Alpha Icons first appeared on WindowsXP.

I would still like to know how it figures it out from the Icon image masks!

"Timo Kunze" <TKunz...@gmx.de> wrote in message

news:utEHECk3...@TK2MSFTNGP12.phx.gbl...

0 new messages