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

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.

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

How to add an image with transparency to a TDbgrid column in delphi?

I am trying to add an image to a column on a TDbgrid that takes transparency into account. When drawing the image from a TImageList on the canvas in the DBGridDrawColumnCell procedure, I need the background of the image (the same color as the pixel in the lower left corner) to take on transparency. I want this transparency area to show the highlight color or non-highlight color, especially when themes are used, such as Aero. I have been able to accomplish this in older versions of Windows with color values of clHighlight or clWindow as the background color. But with Aero themes, it always paints a box behind the non-transparent part of the image instead of the gradient blue highlight color that Aero uses. How can I accomplish this?
I believe I am supposed to use alpha channel but I'm not sure how to do this from a TImageList to a canvas. I believe the cell is painted completely with the actual highlight color before I start drawing on the canvas in the cell. I just want to draw the non-transparency part of the image and leave the background.
I was able to finally determine how to display images on a dbgrid with transparency even if themes, such as Aero is used.
I used a regular TImageList and loaded the images that I needed to display on the dbgrid. In my case there were two and they were in icon (ico) format. Instead of transferring the image to a bitmap and then drawing it to the dbgrid canvas as most old code recommends, I simply used the following simple code in the DBGridDrawColumnCell procedure:
if DataCol=0 then
begin
if (MApptsConflict.Value='<none>') then
ImageIndex := 0
else
ImageIndex := 1;
ImageList.Draw(TDBGrid(Sender).Canvas,Rect.Left+2,Rect.Top+2,ImageIndex,True);
end;
This will draw directly to the dbgrid canvas from the TImageList which will give the desired transparency.
UPDATE: I tried it with bmp's loaded in the Timagelist and it worked too.

Delphi PNGImage - Image transparency is not pure

I am using PNG images as main image resource in my application. Since im using Delphi 7, i downloaded PNGImage lib and included it in project. I load images like this:
Form.image.Picture.LoadFromFile(PAnsiChar('\background.png'));
Image has transparent and semi transparent pixels on its border. The problem i get is that transparent pixels are filled with random zoomed part of my desktop with currently opened windows, while i expected to see what is actually located beneath form.
Additionally, form has this properties:
BorderStyle: bsNone;
TransparentColor: true;
Visible: false;
Here is a picture of current state (above black line) and desired:
Can this be fixed somehow or it is how delphi deals with transparency?
To have the form "shade" what's beneath it, use the forms AlphaBlend and AlphaBlendValue properties. The .png image doesn't have to be partially (alpha blended) transparent, but it can be.
If you want the form to be semi-transparent you use Alphablending, that's a limitation of Windows. In addition you can have a certain color fully transparent. In the following sample the forms color is clGray, which is also defined as the Transparent color property in addition to the Transparent property set to True. The image, aligned alClient, is 50% transparent, placed on a TImage which is set as transparent, but even so, it doesn't show up as semi-transparent unless you have AlphaBlending on. Again, this is a limitation of Windows. The best you can do is try with a fairly high value for AlphaBlendingValue (240..250) and a rather light image to find the right compromise.

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.

How to draw PNG over dialog controls

I need to make some thing like a SEMI-transparent glass layer over dialog's controls. The context is when my application wait for a long process to finish all other controls need to be disabled, and an animation is shown on glass layer as waiting-animation.
I am going to draw a semi-transparent PNG image with size of client area, overlapping all other controls. I do the drawing in OnPaint() but image is drawn as background of the dialog.
So my question is how can i draw png image overlap dialog's control??
LRs
You can try with fiddling the WS_CLIPCHILDREN and WS_CLIPSIBLINGS styles, but I'm not sure that will work. I think you will need to draw a custom control on top of all other controls (at the top of the z-order stack) and draw your bitmap on that one (that's the approach I would take - the dialog is supposed to be behind the controls always, so your approach of drawing on the dialog is fighting the system, as it were).
So basically you would draw on the custom control that would cover all other controls, but you don't even need to draw it transparently; you can use the WS_EX_TRANSPARENT and/or WS_EX_LAYERED window style and SetLayeredWindowAttributes() method, as long as you don't need to support operating systems older than win2k.

Resources