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

How to determine whether a HBITMAP has alpha channel or obtain a BITMAPV4HEADER or BITMAPV5HEADER from a HBITMAP?

705 views
Skip to first unread message

Kornél Pál

unread,
Sep 18, 2005, 5:31:30 AM9/18/05
to
Hi,

I want to convert 32-bit (8-bit alpha channel) HICONs to GDI+ bitmaps.

The problem is that GdipCreateBitmapFromHICON and
GdipCreateBitmapFromHBITMAP ignore alpha channel.

I can create bitmaps with aplha channel using GetIconInfo to get hbmColor,
GetObject to get the header and GetBitmapBits to get the bits. Then I pass
these data to GdipCreateBitmapFromScan0.

My only problem is that bmBitsPixel is 32 for icons with alpha channel as
well as for icons without alpha channel. If I use PixelFormat32bppRGB GDI+
uses no alpha channel. If I use PixelFormat32bppARGB icons without alpha
channel are entirely transparent because of the bits that GDI+ treats as
alpha channel are not used.

If I could determine whether a HBITMAP has an alpha channel it could be
passed to GdipCreateBitmapFromScan0 and there were no problem.

If BITMAPV5HEADER could be obtained for a HBITMAP bV5AlphaMask could be used
to determine whether there is an alpha channel.

Thanks in advance for you help.

Kornél


Michael Phillips, Jr.

unread,
Sep 18, 2005, 10:11:37 AM9/18/05
to
You may convert a 32bpp HICON to a gdi+ alpha bitmap
as follows:

1) Use GetIconInfo to obtain the bitmap AND and XOR
masks.
2) Use GetDIBits to get the AND and XOR bits.
3) Create a PixelFormat32bppARGB gdi+ bitmap
with the same width and height of the icon.
4) Create a loop and use LockBits to fill in the bits
of the gdi+ bitmap. The alpha channel is represented
by the AND bitmap mask. Sample the AND mask using
GetPixel to obtain the color (i.e. either white or black ).
Everywhere the AND bitmap has the color white, you
set the gdi+ alpha channel to 0 (transparent). Everywhere the AND
bitmap is black, you set the gdi+ alpha channel to opaque (0xFF).
The RGB pixels comes from the XOR bitmap.

If you wish to create a gdi bitmap, then create a DIBSECTION using
CreateDIBSection using a BITMAPV5HEADER. Follow the same
algorithm as above.

I hope this helps.

"Kornél Pál" <anon...@discussions.microsoft.com> wrote in message
news:%23qOB9OD...@TK2MSFTNGP12.phx.gbl...

Michael Phillips, Jr.

unread,
Sep 18, 2005, 10:22:06 AM9/18/05
to
How to determine if the HICON was created with a BITMAPV5HEADER
as a true alpha channel icon?

An icon is normally created with an XOR and AND mask regardless
of the bit depth.

GetIconInfo followed by GetObject will not reveal a BITMAPV5HEADER.
The size of the header is always 40 for a BITMAPINFOHEADER.

If there is a blank AND mask, then a BITMAPV5HEADER was
used. The AND mask is redundant with an alpha channel bitmap.

In that case, you need to get the pixels in the proper ARGB format.
Use GetDIBits with a BITMAPV5HEADER to do the conversion
for you.


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

Mike D Sutton

unread,
Sep 18, 2005, 5:34:47 PM9/18/05
to

Since GetDIBits() will fill whatever header you send it, there's no way of telling which header was used to create the Bitmap in the
first place. The bV4AlphaMask/bV5AlphaMask member of the extended headers may optionally be filled for BI_BITFIELDS compressed
images so you shouldn't rely on it as the sole indicator. If in doubt simply run a quick scan of the alpha channel of the image and
jump out as soon as you hit any non-0 values.
Hope this helps,

Mike


- Microsoft Visual Basic MVP -
E-Mail: ED...@mvps.org
WWW: Http://EDais.mvps.org/


Kornél Pál

unread,
Sep 19, 2005, 6:44:58 AM9/19/05
to

I've tried GetDIBits(). It has support only for BITMAPINFOHEADER (size=40).
I've tried to specify masks in bmiColors (bmiHeader.biClrUsed is the count
of elements). But it had no effect on the layout of the bits.

So the only solution seems to be to scan the entire image for non-zero alpha
values (as you said) but it is the most lame possible solution.

Kornél


Kornél Pál

unread,
Sep 19, 2005, 7:13:55 AM9/19/05
to
Thanks for you response, you told me a lot of interesting things I learnt
some things but there were some factual errors:

> If there is a blank AND mask, then a BITMAPV5HEADER was
> used. The AND mask is redundant with an alpha channel bitmap.

AND mask is redundant but it isn't blank, it's peresent. It masks the bitmap
as transparent where it is 100% transparend in alpha channel any other alpha
values are opaque in AND mask. So this cannot be used to determine whether
there is an aplha channel. (A lame solution is to scan the AND mask and see
if the alpha value is non-zero at the first 1 value in AND mask. If that
alpha value is 0 there is no alpha channel.)

> In that case, you need to get the pixels in the proper ARGB format.
> Use GetDIBits with a BITMAPV5HEADER to do the conversion
> for you.

GetDIBits() has no support to BITMAPV5HEADER so the results were the same
when I used bV5RedMask...bV5AlphaMask to specify the bit layout of the
bitmap. I tried BI_BITFIELDS along with masks in bmiColors (array size is in
biClrUsed) but I had no effect. In both cases the bits were returned in the
original format (AARRBBGG) where alpha is 0 for non-alpha channel icons and
alpha is used for alpha channel icons. So the result was the same as with
GetBitmapBits() because no bitmask rearrangement was done by GetDIBits()
either in color masks or in alpha mask.

>> Everywhere the AND bitmap has the color white, you
>> set the gdi+ alpha channel to 0 (transparent). Everywhere the AND
>> bitmap is black, you set the gdi+ alpha channel to opaque (0xFF).
>> The RGB pixels comes from the XOR bitmap.

This is what GdipCreateBitmapFromHICON does. (Or has the same result at
least.) But when doing this alpha channel from the XOR mask is lost. As
there are alpha channel and non-alpha channel icons as well, I have to deal
with all of them. If there are less than 32-bits there is not alpha channel
so there is no problem. But an HICON can have 32-bits (I think depending on
screen color depth, because all my HICONs are 32-bit) and I cannot determine
whether there is an alpha mask.

The solution suggested by Mike D Sutton (to scan the entire image for
non-zero alpha mask) works but it is the most lame possible solution.

DrawIconEx knows whether an HICON has alpha mask so it is stored somewhere
but may be only in internal structures of GDI. Having a flag is more
efficient than scanning the entire bitmap.

Do you have any other idea how to determine whether there is an alpha
channel?

Kornél

> "Michael Phillips, Jr." <mphil...@nospam.jun0.c0m> wrote in message

> e15VYxFv...@TK2MSFTNGP12.phx.gbl...

Mike D Sutton

unread,
Sep 19, 2005, 7:21:55 AM9/19/05
to
> I've tried GetDIBits(). It has support only for BITMAPINFOHEADER (size=40).

If you pass it a BITMAPV4HEADER/BITMAPV5HEADER it will quite happily fill those, just make sure that you specify the correct
structure size.

> I've tried to specify masks in bmiColors (bmiHeader.biClrUsed is the count
> of elements). But it had no effect on the layout of the bits.

biClrUsed specifies the number of entries in the palette, the colour masks are optionally written after the header only for images
with the BI_BITFIELDS compression mode set. You shouldn't set biClrUsed for bit-fields compressed images unless you also have a
palette set for them.

> So the only solution seems to be to scan the entire image for non-zero alpha
> values (as you said) but it is the most lame possible solution.

Unfortunately there's nowhere that defines whether the alpha channel has valid data in or whether it's pre-multiplied or not so it's
up to the application to decide these things (or have some other way of storing this information with the image.) The Bitmap format
was never designed to handle alpha data, personally I use the Targa file format which is just as easy to use but also includes
information about the alpha channel and what it contains.
Incidentally, even large graphics applications such as Adobe Photoshop use the alpha channel scan technique, 'lame' or not..

Kornél Pál

unread,
Sep 19, 2005, 8:11:40 AM9/19/05
to
> If you pass it a BITMAPV4HEADER/BITMAPV5HEADER it will quite happily fill
> those, just make sure that you specify the correct
> structure size.

Thanks for mentioning this, you are right. It fills mask fileds for RGB but
unfortunately alpha mask is zero anyway.

> biClrUsed specifies the number of entries in the palette, the colour masks
> are optionally written after the header only for images
> with the BI_BITFIELDS compression mode set. You shouldn't set biClrUsed
> for bit-fields compressed images unless you also have a
> palette set for them.

According to the documentation it can be used:
http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp

"If the biCompression member of the BITMAPINFOHEADER is BI_BITFIELDS, the
bmiColors member contains three DWORD color masks that specify the red,
green, and blue components, respectively, of each pixel."

OK, I belive that there is no other, way so I will use bitmap scanning for
alpha channel.

Thanks for your help.

Kornél

Michael Phillips, Jr.

unread,
Sep 19, 2005, 9:16:20 AM9/19/05
to
In my own code, I don't care if the 32bpp icon was created from
an alpha channel bitmap. Since the AND mask represents
the alpha channel, I use it to create the alpha channel bitmap.

Additionally, I create the AND mask whether is was present
or not.

32bpp are very small. It is no effort to resample the bits.

The important thing to remember with 32bpp bitmaps is
that they are formatted a BGR. Alpha channel bitmaps
are ARGB. As you already stated, not all GDI functions
work with bitmaps formatted as ARGB.

I premultiply the alpha channel so that even with a BGR
32bpp bitmap the alpha channel is present in the bits and
can be used with all GDI functions.


"Kornél Pál" <anon...@discussions.microsoft.com> wrote in message

news:eIBg3sQv...@TK2MSFTNGP09.phx.gbl...

Kornél Pál

unread,
Sep 19, 2005, 10:18:49 AM9/19/05
to
Thanks for all your help.

I managed to solve the problem. Altough I think scanning the entire bitmap
for non-zero alpha mask is a lame solution this seems to be the only
solution to determine whether a HICON has alpha channel. If it has no alpha
channel I use GdipCreateBitmapFromHICON.

Kornél

"Michael Phillips, Jr." <mphil...@nospam.jun0.c0m> wrote in message

e6INSxRv...@TK2MSFTNGP12.phx.gbl...

Mike D Sutton

unread,
Sep 19, 2005, 8:28:26 AM9/19/05
to
> According to the documentation it can be used:
> http://msdn.microsoft.com/library/en-us/gdi/bitmaps_1rw2.asp
>
> "If the biCompression member of the BITMAPINFOHEADER is BI_BITFIELDS, the
> bmiColors member contains three DWORD color masks that specify the red,
> green, and blue components, respectively, of each pixel."

The bmiColors array can be used to store the bit-fields, but in these cases the biClrUsed member should not be set - it's there to
specify the palette size only, not the size of the bit-fields. Technically, specifying 12/16 in biClrUsed of a BI_BITFIELDS header
means that you're including 3/4 colours of palette and the bit-fields follow that..

0 new messages