I'm trying to create a high quality icon (means: suitable for Win Vista/7/8) from a PNG file programmatically in C# for use as shortcut icons. Since the Bitmap.GetHIcon() function doesn't support these kind of icons, and I want to avoid external dependencies or libraries, I'm currently using a slightly modified ICO writer I found here on SO. I have working code but I'm experiencing some glitches in the way Windows displays these icons. The relevant code is:
// ImageFile contains the path to PNG file
public static String IcoFromImageFile(String ImageFile) {
//...
Image iconfile = Image.FromFile(ImageFile);
//Returns a correctly resized Bitmap
Bitmap bm = ResizeImage(256,256,iconfile);
SaveAsIcon(bm, NewIconFile);
return NewIconFile;
}
// From: https://stackoverflow.com/a/11448060/368354
public static void SaveAsIcon(Bitmap SourceBitmap, string FilePath) {
FileStream FS = new FileStream(FilePath, FileMode.Create);
// ICO header
FS.WriteByte(0); FS.WriteByte(0);
FS.WriteByte(1); FS.WriteByte(0);
FS.WriteByte(1); FS.WriteByte(0);
// Image size
// Set to 0 for 256 px width/height
FS.WriteByte(0);
FS.WriteByte(0);
// Palette
FS.WriteByte(0);
// Reserved
FS.WriteByte(0);
// Number of color planes
FS.WriteByte(1); FS.WriteByte(0);
// Bits per pixel
FS.WriteByte(32); FS.WriteByte(0);
// Data size, will be written after the data
FS.WriteByte(0);
FS.WriteByte(0);
FS.WriteByte(0);
FS.WriteByte(0);
// Offset to image data, fixed at 22
FS.WriteByte(22);
FS.WriteByte(0);
FS.WriteByte(0);
FS.WriteByte(0);
// Writing actual data
SourceBitmap.Save(FS, System.Drawing.Imaging.ImageFormat.Png);
// Getting data length (file length minus header)
long Len = FS.Length - 22;
// Write it in the correct place
FS.Seek(14, SeekOrigin.Begin);
FS.WriteByte((byte)Len);
FS.WriteByte((byte)(Len >> 8));
FS.Close();
}
This compiles and works, but with one problem. Windows displays the icon on the shortcut incorrectly. I do this also programatically, but it occurs even if I do it manually (via File Properties, Change Icon). The problem is that the icon is cut off (the image itself displays correctly). It depends on the image, but usually only around 20% of the actual icon is shown. If I open the file in an image viewer like XNView it displays completely and correct, but MS Paint doesn't. I made this screenshot, along with a correctly displayed icon for comparison
I suspect the error lies in the ICO saving method, but even after comparing them to normally displayed ICOs in a Hex editor, the header gets written correctly but the PNG image part itself seems different. Has anyone an idea? I also welcome better, less hacky solutions.