Create high quality ICO file programmatically

I am trying to create a high-quality icon (meaning: suitable for Win Vista / 7/8 ) from a PNG file programmatically in C # for use as shortcuts. Since the Bitmap.GetHIcon () function does not support such icons, and I want to avoid external dependencies or libraries, I am currently using the slightly modified ICO writer I found here in SO . I have working code, but I am having some problems displaying these icons on Windows. Relevant Code:

// 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 does not display the icon on the shortcut correctly. I do this also programmatically, but it happens even if I do it manually (via File Properties, Change Icon). The problem is that the icon is cropped (the image itself is displayed correctly). It depends on the image, but usually only about 20% of the actual icon is displayed. If I open the file in an image viewer such as XNView, it will display completely and correctly, but MS Paint will not. I took this screenshot along with a correctly displayed icon for comparison

enter image description here

I suspect that the error lies in the method of saving ICOs, but even after comparing them with the usually displayed ICOs in the hex editor, the title is spelled correctly, but the part of the PNG image itself seems different. Anyone have an idea? I also welcome better, less hacker solutions.

+8
source share
1 answer

Your ico file is configured to preserve the length of the embedded bitmap with only 16-bit precision, but the PNG file is too large (more than 65535 bytes), so the length record overflows.

those. The following lines are incomplete:

 // Write it in the correct place FS.Seek(14, SeekOrigin.Begin); FS.WriteByte((byte)Len); FS.WriteByte((byte)(Len >> 8)); 

You can add the following lines:

 FS.WriteByte((byte)(Len >> 16)); FS.WriteByte((byte)(Len >> 24)); 

Like cleanliness and performance, I would generally avoid all of these individual records and simply use write overload with a byte array parameter. In addition, instead of some complicated Save-To-File, you can search for Save-to-MemoryStream, then one record for the header (which can now use the PNG length in bytes) and one record for copying PNG data from the memory stream to the file.

Another point that you really need to solve is to manage IDisposable resources . Even if you do not need it yet, since you have not encountered any problems, it will someday bite you, and if you even have a rather small code base with all kinds of unrelated supplies, it will be very difficult for you to find the source of the leak and / or dead end. In general: never call Close if you really cannot avoid it, instead wrap FileStream in a using block. Likewise, Image and Bitmap are disposable and allocate their own resources, although at least you cannot get any problems with locking (AFAIK - but it's better to be safe than sorry.

+7
source share

All Articles