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

How to get a Bitmap from a 32-bit alpha-blended icon?

310 views
Skip to first unread message

M. Shawn Dillon

unread,
Sep 14, 2003, 8:45:48 PM9/14/03
to
Does anyone have code that will preserve the alpha-blend information in an
XP/2003 icon resource, while converting it to a Bitmap?

Basically, I have code that retrieves icons, but all my attempts to convert
them to PixelFormat.Format32bppArgb Bitmaps loses the alpha information.

The goal is to have a method that will accept a file path and either a
background color or Bitmap on which to paint the shell icon, and return the
resulting pre-blended Bitmap. This will be used to show an Explorer-like
view of the server in a Web application.

public Bitmap ShellItemBitmap(string path, Color currentBackground);
public Bitmap ShellItemBitmap(string path, Bitmap currentBackground);

Thanks in advance,
M. Shawn Dillon
shawn....@insightbb.nospam.com
Senior Application Developer
MaximumASP, LLC.


Michael Phillips, Jr.

unread,
Sep 15, 2003, 10:11:46 AM9/15/03
to
The gdi+ decoder for bitmaps will only create a PixelFormat32RGB image for
the
case that you describe. If you want a PixelFormat32ARGB bitmap, you will
have
to use the BITMAPV5HEADER which supports an Alpha Channel and create
your own decoder and encoder.

It is easy, you can use memory streams and/or file io. You can even do
clipboard
operations with the CF_DIBV5 clipboard format.

Microsoft's knowledgebase has numerous articles on how to load and save
bitmap images. Most of the GDI API's accept the BITMAPV5HEADER
where you would normally use the BITMAPINFOHEADER.

The BITMAPV5HEADER is supported on Windows 2000, Windows XP and
Windows 2003 Server.


"M. Shawn Dillon" <shawn....@insightbb.moc> wrote in message
news:ukF31Kye...@TK2MSFTNGP11.phx.gbl...

M. Shawn Dillon

unread,
Sep 16, 2003, 9:43:37 PM9/16/03
to
Thanks Michael, I appreciate the response, but could you or someone as
knowledgeable in this area verify that the steps below are on the right
track (or provide some links that might help)? While I understand that this
is the way to proceed from your response and other articles I've found, and
I have no problem wrapping Win32 API calls and structures myself, right now
I just can't seem to get my head wrapped around the selection and sequence
of these calls that will accomplish the desired result.

To be fair, I'm rather new to the graphics APIs and don't understand many of
the terms yet, but I'm fairly proficient with using the Win32 APIs from C#.

I've found the
http://support.microsoft.com/default.aspx?scid=kb;en-us;318876 article that
describes how, in C++, to create an alpha-blended cursor or icon, so I'm
proceeding from that, but backwards (creating a bitmap from an icon).

1. Given an HICON, use GetIconInfo to grab HBITMAPs for the mask (does this
contain the alpha information?) and color info.
2. Create and fill out a BITMAPV5HEADER as in the above-referenced article.
2. Get a handle to a device context using GetDC.
3. Create a DIBSection(?) using CreateDIBSection that will allocate the
memory required to store the new bitmap data.
4. Here is where it breaks down. I'm not sure how to draw the HBITMAPs
returned from GetIconInfo onto the DIBSection, or how to convert the result
back into a managed System.Drawing.Bitmap...

Help! :)

Thanks again,


M. Shawn Dillon
shawn....@insightbb.nospam.com
Senior Application Developer
MaximumASP, LLC

"Michael Phillips, Jr." <m_phil...@nospam.hotmail.com> wrote in message
news:%23$82JN5eD...@TK2MSFTNGP11.phx.gbl...

Michael Phillips, Jr.

unread,
Sep 17, 2003, 12:40:14 PM9/17/03
to
In the knowledge base article, you are creating a handle to an alpha
DIBSection
from scratch. Once you have obtained handles to the mask and color portions
of the icon through the iconinfo structure, you must first create a
DIBSection for the color
bitmap handle as outlined in the article.

Next you must set the alpha channel for each byte of the DIB. You must
extract
the alpha information from the handle to the mask bitmap.

Use:
BITMAP bmMask;
GetObject(hBitmapMask, sizeof(BITMAP), &bmMask);

This will give you access to the alpha bits. You can use the same code in
the article
to clear and set the alpha channel of the color DIBSection byte by byte.

Essentially, you now have an alpha formatted bitmap in a nice memory buffer.

Your next step is to create a System.Drawing.Bitmap with the same width and
height as your
icon but use PixelFormat32ARGB.

You now have an empty Bitmap that you must fill with the bits from your
DIBSection.

You will then have to use unsafe code to copy the DIBSection bits to your
new PixelFormat32ARGB Bitmap.
You use LockBits to access the Scan0 field of the BitmapData structure and
the copy each scanline
from the DIBSection bitmap to your gdi+ bitmap. Both have the same stride,
PixelFormat and image size
so you may copy the whole DIBSection image to your gdi+ bitmap rather than
copy a scanline at a time

I hope this helps.


"M. Shawn Dillon" <shawn....@insightbb.moc> wrote in message

news:uzz$g0LfDH...@TK2MSFTNGP12.phx.gbl...

Michael Phillips, Jr.

unread,
Sep 17, 2003, 7:24:44 PM9/17/03
to
Shawn,

I have an easier solution for you.

1) Create a System.Drawing.Bitmap with the same width and height of the icon
but use PixelFormat32ARGB. This will give you an empty bitmap that you
need to fill with the bits of the icon.
2) Grab the hbmColor and hbmMask from the iconinfo structure.
3) Create a Gdiplus Graphics object from the new System.Drawing.Bitmap that
you created in Step1.
4) Create a System.Drawing.Bitmap from the hbmColor handle.
5) Use DrawImage to copy the bmColor Bitmap from Step 4 to the bitmap
created in Step 1. You now have the color bits set correctly.
Dispose of the Graphics object.
6) Use the following to gain access to the Icon's Mask:
BITMAP bmMask;
GetObject(hbmMask, sizeof(BITMAP), &bmMask);
Each pixel is either a 0 or a 1 representing an alpha of 0 or 255.
There are 8 pixels packed into each byte.
7) Use unsafe LockBits to gain access the color bitmap bits.
Now clear and/or set the Alpha Channel.

for ( int i = 0; i < bmData.Height; i++)
{
// Color portion of the Icon
unsigned int* Bits = (unsigned int*)bmData.Scan0 + (
bmData.Height - 1 - i) * bmData.Stride;
// For a 1bpp Mask there are 8 pixels packed into 1 byte
// Each pixel is an index into a color palette. In this case the
index represents 0 or 255
unsigned char* MaskBits = (unsigned char*)bmMask.bmBits +
(bmMask.bmHeight - 1 - i) * bmMask.bmWidthBytes;
int col = 0;

for ( int j = 0; j < bmData.Width; j++ )
{
ARGB color = Bits[j];
// grab the alpha from the Icon Mask
unsigned char Alpha = ( (*MaskBits << col ++) & 0x80 ) ?
255 : 0 ;
// Set or clear the alpha channel
Bits[j] = Color::MakeARGB(Alpha, color.GetRed(),
color.GetBlue(), color.GetGreen());

if ( ! (col % 8) ) // when all 8 pixel read, advance to
the next pixel
MaskBits++;
}
}

Since I haven't tested this code, make sure that you don't cross the Icon
Mask's scanline.
The Width of the Mask's Bitmap represents pixels. There should be (Width >>
3) bytes
in each scanline.

"Michael Phillips, Jr." <m_phil...@nospam.hotmail.com> wrote in message

news:Ojo%23ipTf...@TK2MSFTNGP12.phx.gbl...

Michael Phillips, Jr.

unread,
Sep 18, 2003, 12:32:07 PM9/18/03
to
Sorry for the last post.

I lost track over what you are trying to accomplish.

To preserve the alpha channel, you must use the technique outlined in the
article using
a BITMAPV5HEADER. Gdi+ will load an icon in PixelFormat32bppARGB.
Gdi+ converts everything internally to 32bpp. By design it will only save
to the PNG
format as there is no encoder for icons. Any bitmap image with an alpha
channel
will lose the alpha channel when loaded or saved, unless you use your own
encoder/decoder.

Getting a handle to the Icon that Gdi+ produces and using it to get an
ICONINFO
structure will leave you disappointed. I tried to get BITMAP info from the
handles
to the color and mask bitmaps. The information returned does not give you
access
to the bits. That field is null!

I believe you need to roll your own encoder/decoder if you wish to work with
all icon formats and all bitmap formats . That is why I suggest the
following article:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnwui/html/msdn_icons.asp

It includes a sample application that will help you understand the icon
format and provides
links to other articles about DIB's and Bitmap's. With the information
outlined in these
articles, you should have no trouble creating a really usefull
encoder/decoder for bitmaps
and icons supporting all color formats.

Using the BITMAPV5HEADER and CreateDIBSection API's, You should be able to
create bitmaps
with color formats ranging from 1bpp to 64bpp. By using Gdi+, you can
convert between the other
image formats supported and your enhanced bitmap and icon encoder/decoder.

"Michael Phillips, Jr." <m_phil...@nospam.hotmail.com> wrote in message

news:OsRsiLX...@tk2msftngp13.phx.gbl...

M. Shawn Dillon

unread,
Sep 18, 2003, 10:18:02 AM9/18/03
to
Michael,

Thank you! This is exactly what I needed.

"Michael Phillips, Jr." <m_phil...@nospam.hotmail.com> wrote in message

news:Ojo#ipTfD...@TK2MSFTNGP12.phx.gbl...

CT

unread,
Oct 5, 2003, 7:22:28 AM10/5/03
to
Hi,
 
I am also trying to acheive a similar result. I have a windows HICON converting to a GDI+ bitmap for use in an ImageList associated with a listview/treeview. The alpha information is "lost" ie black  (although the resulting bitmap is 32bppArgb). My code snippet...
 
System.Drawing.Image img = Bitmap.FromHicon(shfi.hIcon);
 
I think this should work however I suspect it is related to the bug in KB article 822488
 
 
Chris Thompson
 
 
"M. Shawn Dillon" <shawn....@insightbb.moc> wrote in message news:ukF31Kye...@TK2MSFTNGP11.phx.gbl...
0 new messages