Re: GdipCreateHBITMAPFromBitmap + PixelFormat32bppARGB
- From: "Michael Phillips, Jr." <mphillips53@xxxxxxxxxxxxxxx>
- Date: Sat, 6 Aug 2005 17:10:32 -0400
The Windows ImageList control uses GDI for drawing.
The Windows bitmap specification was drawn up for Windows 3.1
a 16 bit operating system. Alpha blended bitmaps were not supported.
The documentation for AlphaBlend function implies that Windows GDI
uses premultiplied alpha channels for drawing bitmaps that contain
an alpha channel.
My test case uses GDI to draw alpha blended bitmaps.
The test image is a .png file from the PNG Test Image Suite.
I supplied a link in my post.
When you run the test case, clearly you get a bluish tint when you
use GDI to draw the bitmap converted from the .png image.
When you convert the bitmap to use premultiplied alpha, the bluish
tint is gone. The image displays correctly using GDI functions.
The same GDI functions used by the ImageList control.
Gdiplus correctly handles the drawing whether or not you
premultiply the alpha channel that is why I did not use it in
my test case.
If you use an alpha channel HBITMAP generated by gdiplus or one that
you create with CreateDibSection, it will not draw correctly without
premultiplying the alpha channel.
Not only does the above apply to HBITMAPs it also
applies to alpha channel HICONS. GDI will only
display the icons correctly when the alpha channel is
premultiplied.
I used your image file in my test case. Additionally, I created
a 32x32 alpha blended icon from your image.
When I premultiplied the alpha channel and use GDI
to draw the bitmap and icon, the image was drawn
correctly with no bluish tint. If I did not premultiply
the alpha channel, I got a bluish bitmap and a bluish
icon. Again GDI is used by the Microsoft's common
controls and GDI is used extensively to draw bitmaps
and icons for the Windows GUI ( buttons, windows, controls, etc.).
I have tested BitBlt, AlphaBlend, DrawIcon and TransBlt
on your image. The image was drawn without a bluish tint
once I premultiplied the alpha channel.
I am not convinced that you have discovered a bug!
"Jonathan Gilbert" <logiclrd@xxxxxxxxxxx> wrote in message
news:7B171912-10BF-4723-993C-9D7F5B0BF521@xxxxxxxxxxxxxxxx
> "Michael Phillips, Jr." wrote:
>> I don't believe there is a bug!
>>
>> For background please see:
>> http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/bitmaps_3b3m.asp
>>
>> When you call GetHBITMAP and the bitmap has an alpha channel,
>> you will get a bluish tint in the areas where the bitmap is transparent.
>> Your bitmap has a Format32bppARGB. It requires special handling.
>>
>> This is by design. See the above link for an explanation.
>
> Are you suggesting that GDI+ uses the AlphaBlend GDI function in its
> implementation of GdipCreateHBITMAPFromBitmap? I can find no evidence of
> this. The GdiPlus.dll PECOFF image does not statically import the
> AlphaBlend
> function; in fact, the string 'AlphaBlend' does not appear anywhere within
> the file, neither as an ANSI or a Unicode string. The only function other
> than AlphaBlend which uses the BLENDFUNCTION structure is
> UpdateLayeredWindow, which hardly seems applicable in the implementation
> of
> GdipCreateHBITMAPFromBitmap.
>
> Even if this structure were being used by GdipCreateHBITMAPFromBitmap in
> some way, this does not explain the behaviour. The expected result of not
> premultiplying the alpha channel would be that the pixels would simply be
> too
> bright. If the function failed to clamp the values for each colour
> component,
> then they would wrap around, causing very noticeable artifacting wherever
> the
> sum of the source and the destination exceeded 255.
>
> The actual result that is being seen is that only the blue channel of the
> specified background colour is being used. The red & green channels are
> being
> treated as black. Did you check out the screenshot I showed?
>
>> If you first convert the bitmap to Format32bppPARGB and then call
>> GetHBITMAP, you image will display without a bluish tint.
>
> My testing indicates otherwise. Even with the alpha channel premultiplied,
> I
> still get a bluish tint. I tested this by altering my second test case,
> starting at line 230, to read the following:
>
> Bitmap test_source(256, 1, PixelFormat32bppPARGB);
>
> for (int i=0; i < 256; i++)
> test_source.SetPixel(i, 0, Color(/* a */ i, /* r, g, b */ i, i, i));
>
> The output image is identical; it appears that GdipCreateHBITMAPFromBitmap
> is aware of the difference between PixelFormat32bppARGB and
> PixelFormat32bppPARGB and compensates correctly for whichever one it is
> not
> natively processing (or has a separate code path for each).
>
>> Keep in mind that the original design of the GDI Bitmap did not include
>> an alpha channel. You can see this by examining the BITMAPINFOHEADER.
>>
>> Microsoft later introduced the BITMAPV5HEADER which allows for
>> an alpha channel.
>
> This shouldn't matter, though, because only the output is a GDI Bitmap.
> The
> two inputs to the function are:
>
> - a GDI+ Bitmap object, and
> - a GDI+ Color value.
>
> Both of these incorporate alpha channel support, and it is properly
> implemented elsewhere in the library.
>
>> In my test case, I use the GDI functions to display the HBITMAPS.
>> You will get the same results if you simply use the Gdiplus Graphics
>> API.
>>
>> Below is a test case that demonstrates the above:
>
> I have not investigated your test case very closely, but it does not seem
> to
> be applicable to the situation at hand. You also did not include the test
> image you used, which is pertinent in this case because you use its first
> pixel as the background colour.
>
> However, there are some issues that were immediately obvious to me.
> Firstly:
>
>> private void Form1_Load(object sender, System.EventArgs e)
>> {
>> this.bOpaque = true;
>> this.BackColor = Color.White;
>> this.bm = new Bitmap("c:\\temp\\PP0N6A08.png");
>>
>> SelectObject(this.hMemDC, this.hOldBitmap );
>> DeleteObject(this.hBitmap);
>> DeleteDC(this.hMemDC);
>>
>> this.hBitmap = bm.GetHbitmap(this.bm.GetPixel(0,0));
>> IntPtr hDC = GetDC( (IntPtr)null );
>> this.hMemDC = CreateCompatibleDC(hDC);
>> ReleaseDC( (IntPtr)null, hDC );
>> this.hOldBitmap = SelectObject(hMemDC, hBitmap );
>> }
>
> As far as I can tell, the middle calls to SelectObject, DeleteObject and
> DeleteDC here occur before all other GDI-related initialization. The
> hMemDC
> and hOldBitmap members will still be IntPtr.Zero at this point. This seems
> rather odd, but the APIs are probably robust enough to handle this... :-)
>
> The other thing I noticed about it is that it seems to assume that the
> problem with the blue tinge is related to how the bitmap is painted, and
> not
> a deficiency of the bitmap data itself. This is a flawed assumption; when
> the
> bug in question manifests, the resulting GDI HBITMAP contains the blue
> tinge
> directly in the bitmap data, and nothing that is subsequently done can
> remove
> it (since the pixels' alpha values are destroyed in the process).
>
> This also causes problems with people who use Visual Studio's built-in
> ImageList editor. The ImageList, as added to a Form & edited in the IDE,
> is
> serialized and stored in the .resx file. Since the IDE uses a .NET
> ImageList
> itself when editing, the serialized form is
> post-GdipCreateHBITMAPFromBitmap,
> meaning that the blue tinge visible even in the IDE before compiling the
> code
> is permanently stored in the resulting resources, which are subsequently
> painted correctly. In other words, the problem is not the painting
> operation,
> but the prior conversion which produced a broken bitmap.
>
> Are you still convinced that there is no bug here? =/
>
> Jonathan Gilbert
>
.
- Follow-Ups:
- Re: GdipCreateHBITMAPFromBitmap + PixelFormat32bppARGB
- From: Jonathan Gilbert
- Re: GdipCreateHBITMAPFromBitmap + PixelFormat32bppARGB
- References:
- Re: GdipCreateHBITMAPFromBitmap + PixelFormat32bppARGB
- From: Jonathan Gilbert
- Re: GdipCreateHBITMAPFromBitmap + PixelFormat32bppARGB
- Prev by Date: Re: How can i change the icon of a button in the propertygrid?
- Next by Date: .Net Framework Memory Leak
- Previous by thread: Re: GdipCreateHBITMAPFromBitmap + PixelFormat32bppARGB
- Next by thread: Re: GdipCreateHBITMAPFromBitmap + PixelFormat32bppARGB
- Index(es):
Loading