views:

272

answers:

3

I've been fussing with this for the better part of the night, so maybe one of you can give me a hand.

I have found GDI+ DrawImage in C# to be far too slow for what I'm trying to render, and from the looks of forums, it's the same for other people as well.

I decided I would try using AlphaBlend or BitBlt from the Win32 API to get better performance. Anyway, I've gotten my images to display just fine except for one small detail—no matter what image format I use, I can't get the white background to disappear from my (transparent) graphics.

I've tried BMP and PNG formats so far, and verified that they get loaded as 32bppargb images in C#.

Here's the call I'm making:

// Draw the tile to the screen.
Win32GraphicsInterop.AlphaBlend(graphicsCanvas, destination.X, destination.Y, this.TileSize, this.TileSize,
                                this.imageGraphicsPointer, tile.UpperLeftCorner.X, tile.UpperLeftCorner.Y,
                                this.TileSize, this.TileSize,
                                new Win32GraphicsInterop.BLENDFUNCTION(Win32GraphicsInterop.AC_SRC_OVER, 0,
                                                                                   Convert.ToByte(opacity * 255),
                                                                                   Win32GraphicsInterop.AC_SRC_ALPHA));

For the record, AC_SRC_OVER is 0x00 and AC_SRC_ALPHA is 0x01 which is consistent with what MSDN says they ought to be.

Do any of you guys have a good solution to this problem or know a better (but still fast) way I can do this?

+1  A: 

Graphics.DrawImage() speed is critically dependent on the pixel format. Format32bppPArgb is 10 times faster than any other one on any recent machine I've tried.

Also make sure you the image doesn't get resized, be sure to use a DrawImage() overload that sets the destination size equal to the bitmap size. Very important if the video adapter's DPI setting doesn't match the resolution of the bitmap.

Hans Passant
I'm not sure how to get my image into Format32bppPArgb...it loads as Format32bppArgb. Any thoughts?
Ed Altorfer
Use the Bitmap constructor that lets you specify the PixelFormat. Draw the original bitmap into it with Graphics.FromImage().
Hans Passant
How do I convert back from `Graphics` to an `Image`?
Ed Altorfer
I figured it out. Thanks for the help...
Ed Altorfer
A: 

Have you tried an opacity of just 255 rather than a calculated one?

This blog post describes what you're trying to do:- http://blogs.msdn.com/andreww/archive/2007/10/10/preserving-the-alpha-channel-when-converting-images.aspx

Critical thing is that he carries out a conversion of the image to make the alpha channel compatible..

JonB
+1  A: 

Ok. From a pure Win32 perspective:

In order for AlphaBlend to actually alpha blend... it needs the source device context to contain a selected HBITMAP representing an image with 32bpp bitmap with a pre-multiplied alpha channel. To get a device bitmap with 32bpp you can either call one of the many functions that will create a screen compatible device bitmap and hope like hell the user has selected 32bpp as the desktop bitdepth. OR, ensure that the source bitmap is a DIBSection. Well, the library or framework that is creating it from the loaded image for you.

So, C# is loading your images with 32bpp argb, BUT, how are you converting that C# representation of the bitmap into a HBITMAP? You need to ensure that a DIB Section is being created, not a DDB (or device dependent bitmap), and that the DIB Section is 32bpp.

Chris Becke