How to convert an image to an icon without losing transparency?
I have PNG images which I need to convert to an icon before displaying it.
This is how I did it:
public Icon ImageToIcon(Image imgTest)
{
Bitmap bitmap = new Bitmap(imgTest);
Icon icoTest;
IntPtr iPtr = bitmap.GetHicon();
icoTest = (Icon) Icon.FromHandle(iPtr).Clone();
return icoTest;
}
I lose transparency after doing this, alpha transparent images are not rendered as expected....can this be solved?
No, there's a lot more to it. Icons have a pretty elaborate internal structure, optimized to work reasonably on 1980s hardware. An icon image has three bitmaps, one for the icon, a monochrome bitmap that indicates what parts of the image are transparent and another monochrome bitmap that indicates what parts are reversed. Generating those monochrome bitmaps is pretty painful, .NET doesn't support them. Nor does Bitmap.GetHicon() make an attempt at it. You'll need a library to do the work for you.
Vista gave some relief, it started supporting icons that contain a PNG image. You'll have a shot at generating it with your own code. Like this:
public static Icon IconFromImage(Image img) {
var ms = new System.IO.MemoryStream();
var bw = new System.IO.BinaryWriter(ms);
// Header
bw.Write((short)0); // 0 : reserved
bw.Write((short)1); // 2 : 1=ico, 2=cur
bw.Write((short)1); // 4 : number of images
// Image directory
var w = img.Width;
if (w >= 256) w = 0;
bw.Write((byte)w); // 0 : width of image
var h = img.Height;
if (h >= 256) h = 0;
bw.Write((byte)h); // 1 : height of image
bw.Write((byte)0); // 2 : number of colors in palette
bw.Write((byte)0); // 3 : reserved
bw.Write((short)0); // 4 : number of color planes
bw.Write((short)0); // 6 : bits per pixel
var sizeHere = ms.Position;
bw.Write((int)0); // 8 : image size
var start = (int)ms.Position + 4;
bw.Write(start); // 12: offset of image data
// Image data
img.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
var imageSize = (int)ms.Position - start;
ms.Seek(sizeHere, System.IO.SeekOrigin.Begin);
bw.Write(imageSize);
ms.Seek(0, System.IO.SeekOrigin.Begin);
// And load it
return new Icon(ms);
}
Tested on .NET 4.5 and Windows 8.1. Beware of the possibility of "fringes" you'll see on PNG images with transparency on the edges. That only works well when the image is displayed on a well-known background color. Which, by design, an icon can never depend on. A dedicated icon editor will always be the only truly good way to get good looking icons.