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

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.

Related

Common Controls on a Transparent Window?

While there are lots of variations of the question, there doesn't seem to be a specific answer to a simple case of wanting to use built-in common controls on a transparent window using Win32. I don't want the controls to be transparent, I just want the border around it to be transparent. I can't believe MS didn't update the .dll's to handle transparency when they added it, but I guess they forgot? Is there a specific method that works. A button can get close with WS_EX_TRANSPARENT, but flaky where it works most of the time but at times part of the border shows up. Edit controls, change depending on when get focus or not.
So the question is simply:
Is there a way to make common controls on transparent window so there is no white border around them?
If not, is there a good replacement library that does it via owner draw?
If some, which ones and what is the method?
Seems silly to reinvent the wheel just because of the area around the control.
TIA!!
If I am not mistaken, you can take the following steps to achieve this effect.
1.Create a GDI+ Bitmap object with the PixelFormat32bppPARGB pixel format.
2.Create a Graphics object to draw in this Bitmap object.
3.Do all your drawing into this object using GDI+.
4.Destroy the Graphics object created in step 2.
5.Call the GetHBITMAP method on the Bitmap object to get a Windows HBITMAP.
6.Destroy the Bitmap object.
7.Create a memory DC using CreateCompatibleDC and select the HBITMAP from step 5 into it.
8.Call UpdateLayeredWindow using the memory DC as a source.
9.Select previous bitmap and delete the memory DC.
10.Destroy the HBITMAP created in step 5.
This method should allow you to control the alpha channel of everything that is drawn: transparent for the background, opaque for the button.
A similar discussion: Transparent window containing opaque text and buttons

Windows button ignores alpha channel for fully transparent image

I have a radio button that should display an image (style BS_AUTORADIOBUTTON|BS_PUSHLIKE|BS_BITMAP).
I create a bitmap via CreateDIBSection (using a BITMAPINFO with BI_RGB) and obtain a pointer to the raw pixels via the ppvBits, so that I can manipulate them freely.
I use BM_SETIMAGE to set the button's image to the bitmap I created.
So far, I can set the RGB and alpha by manipulating the pixels by hand. I tested that even semi-transparent (non-premultiplied) alpha values look good.
As far as I can tell, everything works, except if all pixels in the image are transparent. In that case, the button apparently ignores the alpha value, simply displaying a rectangle with each pixel having the respective color with full opacity.
I found a hint that Windows - at least in some cases - actually seems to interpret images whose pixels' alpha values are all 0 as completely opaque images:
When the window manager sees a 32bpp bitmap, it looks at the alpha
channel. If it's all zeroes, then it assumes that the image is in 0RGB
format; otherwise it assumes it is in ARGB format
Is this behavior documented somewhere?
Is this behaviour documented somewhere?
Yes! In Raymond's post! :) That's often the way of it, no?
If you look at the foot of the page here you will find a comments box. If you raise your concerns there then MS will most likely fix their documentation. See here for an example of the process they usually follow if they consider the problem serious enough to fix.

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.

GDI fast scroll

I use GDI to create some custom textwidget. I draw directly to the screen, unbuffered.
now i'd like to implement some fast scrolling, that simply pixelshifts the respective part of the framebuffer (and only redraws the newly visible lines).
I noticed that for example the rich text controls does it like this. If i use some GDI drawing functions to directly draw to the framebuffer, over a rich text control, and then scroll the rich text, it will also scroll my drawing along with the text. so i assume the rich text simply pixelshifts it's part of the framebuffer.
I'd like to do the same, but don't know how to do so.
Can someone help? (independant of programming language))
thanks!
The ScrollWindowEx() API function is optimized to do this.
See BitBlt function:
The BitBlt function performs a
bit-block transfer of the color data
corresponding to a rectangle of pixels
from the specified source device
context into a destination device
context.
and the example at the end of its documentation: Capturing an Image:
You can use a bitmap to capture an
image, and you can store the captured
image in memory, display it at a
different location in your
application's window. [...]
In some cases, you may want your
application to capture images and
store them only temporarily. [...] To
store an image temporarily, your
application must call
CreateCompatibleDC to create a DC that
is compatible with the current window
DC. After you create a compatible DC,
you create a bitmap with the
appropriate dimensions by calling the
CreateCompatibleBitmap function and
then select it into this device
context by calling the SelectObject
function.
After the compatible device context is
created and the appropriate bitmap has
been selected into it, you can capture
the image. The BitBlt function
captures images. This function
performs a bit block transfer that is,
it copies data from a source bitmap
into a destination bitmap. [...]
To redisplay the image, call BitBlt a
second time, specifying the compatible
DC as the source DC and a window DC as
the target DC.

How to draw ARGB bitmap using GDI+?

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.

Resources