How to draw ARGB bitmap using GDI+? - image

I have valid HBITMAP handle of ARGB type. How to draw it using GDI+?
I've tried method:
graphics.DrawImage(Bitmap::FromHBITMAP(m_hBitmap, NULL), 0, 0);
But it doesn't use alpha channel.

I've got working sample:
Get info using bitmap handle: image size, bits
BITMAP bmpInfo;
::GetObject(m_hBitmap, sizeof(BITMAP), &bmpInfo);
int cxBitmap = bmpInfo.bmWidth;
int cyBitmap = bmpInfo.bmHeight;
void* bits = bmpInfo.bmBits;
Create & draw new GDI+ bitmap using bits with pixel format PixelFormat32bppARGB
Gdiplus::Graphics graphics(dcMemory);
Gdiplus::Bitmap bitmap(cxBitmap, cyBitmap, cxBitmap*4, PixelFormat32bppARGB, (BYTE*)bits);
graphics.DrawImage(&bitmap, 0, 0);

I had similar issues getting my transparent channel to work. In my case, I knew what the background color should be used for the transparent area (it was solid). I used the Bitmap.GetHBITMAP(..) method and passed in the background color to be used for the transparent area. This was a much easier solution that other attempts I was trying using LockBits and re-creating the Bitmap with PixelFormat32bppARGB, as well as cloning. In my case, the Bitmap was ignoring the alpha channel since it was created from Bitmap.FromStream.
I also had some very strange problems with the background area of my image being changed slightly. For example, instead of pure white, it was off white like 0xfff7f7. This was the case whether I was using JPG (with blended colors) or with PNG and transparent colors.
See my question and solution at
GDI+ DrawImage of a JPG with white background is not white

Ah... but .Net doesn't use HBITMAP and GDI+ is a C++ library atop the basic Windows GDI, so I'm assuming you're using non-.Net C++.
GDI+ has a Bitmap class, which has a FromHBITMAP() method.
Once you have the GDI+ Bitmap instance, you can use it with the GDI+ library.
Of course, if you can write your program in C# using .Net it will be a lot easier.

Related

Semi-transparent pixel support in GDI+ Graphics.DrawImage() methods

I need to draw 32-bit PNG images with semi-transparent pixels loaded into an ImageList control on a Graphics when clip rectangles may be applied to this drawing. It turned out that I can't do this with the Graphics.DrawImage() method. The translucent pixels simply became gray when I tried to call some overloaded versions of Graphics.DrawImage.
As an example, look at the following picture:
The picture above was created with the following redefined OnPaint method of the form:
protected override void OnPaint(PaintEventArgs e)
{
imageList1.Draw(e.Graphics, 10, 30, 0);
e.Graphics.DrawImage(imageList1.Images[0], 10, 90);
base.OnPaint(e);
}
As you can see, the first ImageList.Draw() method based on the Win32 API ImageList_DrawEx function renders the translucent pixels correctly, while the GDI+ Graphics methods don't. I would be glad to use ImageList.Draw as it does the work correctly, but GDI+ clip rectangles do not work with it (because of its GDI nature).
Is there a way to draw 32-bit PNG images with semi-transparent pixels correctly with pure GDI+ methods if they can be limited by GDI+ clip rectangles?
If it may help, I uploaded the image into the ImageList control at design time this way:
Dropped the ImageList control onto the designer's surface.
Set the ColorDepth property to Depth32Bit.
Set the ImageSize property (48, 48 for that test icon).
Clicked the ellipsis button in the editor of the Images property and added the icon in the Images Collection Editor with its Add button.
The test Mobile Phone Icon of the size 48x48 I used can be downloaded from this source.
You might want to check the Graphics Property CompositingMode.
It should be set to
e.Graphics.CompositingMode = CompositingMode.SourceOver;.
If not, the graphics object is not using transparency. I assume that this is done implicitly by the ImageList control if you use its draw method.

drawing in Windows memory device context - resolution?

I am trying to export a plot generated by my program in the form of a bitmap. No problem with creating a bitmap in memory (with CreateDIBSection) and saving it on the disk (using GDI+). To draw I have to use device context, and the only one that is easily available is compatible with the screen. So I create a compatible dc, select the bitmap I already created into this device context and I am ready to draw and print into the bitmap. And it works - but it gives me no control over the size of the plot (note: size of the plot, not size of the bitmap). If I understand correctly what is happening mapping modes follow DPI of the screen DC which in turn means size of the plot (and text I put on the plot) is different on different computers.
Is there any way of changing the DPI resolution for the device context? Or perhaps there exist a better way of doing what I am trying to do? Perfect solution would be to ask user for the pixel bitmap size and be able to draw a plot that nicely fits the bitmap.
You don't have to use device context to draw now that you already use Gdiplus over GDI. You just associate your Gdiplus::Graphics object with a Gdiplus::Bitmap instead of HDC. Units and transformations let alone bitmap size are all independent of the device. Hope that helps.
Gdiplus::Bitmap bitmap( L"miranda_kerr.png" ); // draw over existing
Gdiplus::Graphics graphics( &bitmap );
Gdiplus::Pen pen( Gdiplus::Color(255,0,0));
Gdiplus::Status status = graphics.DrawLine( &pen, 20, 20, 100, 500 );
//...

Displaying Icons stored as resources with alpha using GDIPlus (WIn32 C++)

I have an icon with partial alpha (alpha values between 0 and 255) that I want to display using GDIPlus. When using the Bitmap constructor of GDI+ that takes the direct filename, the file displays properly. However, when loading from resource, it has a problem recognizing alpha. I looked on MSDN, and there are problems with alpha: http://msdn.microsoft.com/en-us/library/windows/desktop/ms536318.aspx. By retrieving the ICONINFO structure from the Icon, I can get rid of the fully transparent pixels, however, the partially transparent pixels still appear either as fully opaque or fully transparent.
I wanted to know how to create a Win32 Bitmap from an Icon in resource with the partial alpha values.
You can use LoadResource to get a pointer to the icon and and its image data. You can pass the pointer to the image data to the appropriate Bitmap constructor. This is a bit of a chore because icons have a peculiar resource format.
If possible, it would be simpler to store your image as a transparent (i.e. 32bpp argb) bitmap. In this case you can use LoadImage with LR_CREATEDIBSECTION.
Update
Apparently LoadIcon does load the alpha correctly. It would appear that the problem is GdiPlus not respecting the alpha when you construct a GdiPlus::Bitmap from an HICON. What you could do is:
Use LoadIcon to load the icon.
Use GetIconInfo to get the ICONINFO. hbmColor is the handle of the transparent bitmap.
Use GetDIBits to get the bitmap bits from hbmColor.
Pass the data to the Bitmap constructor that takes bits and understands alpha.
The alpha channel is disturbed after you call LoadIcon. The Win32 APIs that load icons, e.g. LoadIcon, LoadImage, etc. are well proven. They reliably load icons with partial alpha.
You need to investigate the code that executes after the icon has been loaded. I can't give you a solution or an explanation, but I am confident that LoadIcon is not the culprit.
I wanted to know how to create a Win32 Bitmap from an
Icon in resource with the partial alpha values.
Call GetIcon or GetImage to obtain an HICON. Then call GetIconInfo. The bitmap you need is in the hbmColor field of the ICONINFO struct.

What is the best way to resize a Bitmap in Windows?

So, I am working on a text editor. I use double buffering to paint on to the screen. So basically I have an offscreen bitmap, which I paint on, and then copy it to the screen. Now, when the window for the text editor resizes, I need to resize the offscreen bitmap as well. So what would be a good way to resize the bitmap? I was thinking to maybe delete the old object and create a new bitmap using CreateCompatibleBitmap, but I'm wondering if it's the correct way to do it.
Language : C++ using Win32 API
Using CreateCompatibleBitmap will work, and then you'll want to call BitBlt on it to copy the contents of your existing backbuffer to the resized buffer. I don't think there is a more efficient way to do it using GDI.
If are thinking about using CreateCompatibleBitmap with BitBlt, you might like to look at StretchBlt instead. StretchBlt works like BitBlt but resizes the source image to fit into the destination area.

How to read the original alpha channel from PNG in J2ME?

I'm writing a simple J2ME game that uses PNG images with 8-bit alpha channel. Problem: not all hardware supports full alpha transparency rendering. However, since my game is pretty static in nature (at the beginning, "sprites" are layed out onto background image, based on current screen size, and that's about it), I thought it would be possible to prerender those transparent images directly onto background during game initialization and use that later in game. I can't prerender them in Photoshop as their positions are not known in advance.
But, it seems there is no way to read the original alpha channel on devices that do not support semi-transparency as it gets resampled during PNG loading. Is there some library that can help with that? Or is it a good idea to store alpha channels separately (e.g. as separate 8-bit PNG images) and manually apply them?
Thanks!
PNG Images also have transparency support if you want to create transparent image then you have read RGB data along with alpha channels and process alpha
Image transPNG=Image.createImage("/trans.png"); //load the tranparent image
int rgbData[];
transPNG.getRGB(rgbData, 0,transPNG.getWidth(), 0, 0,transPNG.getWidth(), transPNG.getHeight());
Image tranparentImage=Image.createRGBImage(rgbData, width, height, true); //process alpha
transPNG=null;
Above code shows how to create the transparent image and use.
I cant promise this will help, but you can try this way of reading the alpha channel using standard methods from Java util.
BufferedImage image = ImageIO.read(new File(name));
int[] alpha = new int[1]; //containg alpha-value for one pixel.
image.getAlphaRaster().getPixel(x, y, alpha);
System.out.println(alpha[0]); //gives the alpha value for x,y

Resources