Bitmap.Save to save icon actually saves .png

I need to write a program that will generate 108 combinations of icons (standard windows .ico files) based on a tile image.

I use the System.Drawing.Bitmap class to build each combinaison, and I save them as follows:

Bitmap IconBitmap = new Bitmap(16, 16); // Some processing, writing different parts of the source tileset // ... IconBitmap.Save(Path.Combine(TargetPath, "Icon" + Counter + ".ico"), ImageFormat.Icon); 

But I found out that the saved file is actually PNG. Neither Windows Explorer nor Visual Studio can display it correctly, but GIMP can, and if I open it in the Hex viewer, this is what I see:

 00000000 89 50 4E 47 0D 0A 1A 0A 00 00 00 0D 49 48 44 52 ‰PNG........IHDR 00000010 00 00 00 10 00 00 00 10 08 06 00 00 00 1F F3 FF ..............óÿ 00000020 61 00 00 00 01 73 52 47 42 00 AE CE 1C E9 00 00 a....sRGB.®Î.é.. 00000030 00 04 67 41 4D 41 00 00 B1 8F 0B FC 61 05 00 00 ..gAMA..±..üa... 00000040 00 09 70 48 59 73 00 00 0E C3 00 00 0E C3 01 C7 ..pHYs...Ã...Ã.Ç 00000050 6F A8 64 00 00 00 15 49 44 41 54 38 4F 63 60 18 o¨d....IDAT8Oc`. 00000060 05 A3 21 30 1A 02 A3 21 00 09 01 00 04 10 00 01 .£!0..£!........ 00000070 72 A5 13 76 00 00 00 00 49 45 4E 44 AE 42 60 82 r¥.v....IEND®B`‚ 

Also, if I rename .ico to .png, Windows Explorer may display it correctly.

I have this result, even if I have NOTHING in the bitmap (I directly build it with new and Save , which gives me black png).

What am I doing wrong?

I also tried this, which gave me an awful 16 color icons, but I would prefer to avoid this solution anyway (using the pens):

 Icon NewIcon = Icon.FromHandle(IconBitmap.GetHicon()); FileStream FS = new FileStream(Path.Combine(Target, "Icon" + Counter + ".ico"), FileMode.Create); NewIcon.Save(FS); 
+2
c # bitmap png icons system.drawing
source share
3 answers

It is true that ImageFormat.Icon does not work for writing, as you assumed, .NET just does not support writing .ico files and just flushes PNG data.

There are several projects on CodeProject (and this one ) (and one more ) and this will allow you to write a .ico file, in fact it is not so difficult. The file format is pretty straight forward and supports BMP and PNG data.

0
source share

I made a quick and dirty workaround, I am posting it here for recording (this may help someone who needs a quick solution, like me).

I will not accept this as the correct answer, this is not a real writer. It just writes a 32 bit ARGB bitmap to the ico file using the PNG format (works in Vista or later)

It is based on the Wikipedia ICO file , and some fail and are repeated.

 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 FS.WriteByte((byte)SourceBitmap.Width); FS.WriteByte((byte)SourceBitmap.Height); // Palette FS.WriteByte(0); // Reserved FS.WriteByte(0); // Number of color planes FS.WriteByte(0); 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, 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(); } 
+3
source share

Here is a simple ICO writer that I wrote today that outputs several System.Drawing.Image images to a file.

 // https://en.wikipedia.org/wiki/ICO_(file_format) public static class IconWriter { public static void Write(Stream stream, IReadOnlyList<Image> images) { if (images.Any(image => image.Width > 256 || image.Height > 256)) throw new ArgumentException("Image cannot have height or width greater than 256px.", "images"); // // ICONDIR structure // WriteInt16(stream, 0); // reserved WriteInt16(stream, 1); // image type (icon) WriteInt16(stream, (short) images.Count); // number of images var encodedImages = images.Select(image => new { image.Width, image.Height, Bytes = EncodeImagePng(image) }).ToList(); // // ICONDIRENTRY structure // const int iconDirSize = 6; const int iconDirEntrySize = 16; var offset = iconDirSize + (images.Count*iconDirEntrySize); foreach (var image in encodedImages) { stream.WriteByte((byte) image.Width); stream.WriteByte((byte) image.Height); stream.WriteByte(0); // no pallete stream.WriteByte(0); // reserved WriteInt16(stream, 0); // no color planes WriteInt16(stream, 32); // 32 bpp // image data length WriteInt32(stream, image.Bytes.Length); // image data offset WriteInt32(stream, offset); offset += image.Bytes.Length; } // // Image data // foreach (var image in encodedImages) stream.Write(image.Bytes, 0, image.Bytes.Length); } private static byte[] EncodeImagePng(Image image) { var stream = new MemoryStream(); image.Save(stream, ImageFormat.Png); return stream.ToArray(); } private static void WriteInt16(Stream stream, short s) { stream.WriteByte((byte) s); stream.WriteByte((byte) (s >> 8)); } private static void WriteInt32(Stream stream, int i) { stream.WriteByte((byte) i); stream.WriteByte((byte) (i >> 8)); stream.WriteByte((byte) (i >> 16)); stream.WriteByte((byte) (i >> 24)); } } 
+2
source share

All Articles