private void SaveToStream(Stream stream) { using (var writer = new BinaryWriter(stream, Encoding.UTF8, true)) { // Remove any duplicated resolutions. Done first because this may change the image count. // ValidateImages(); var imageData = new Dictionary <IconEntry, byte[]>(); // Write header new IconHeader { Reserved = 0, Type = 1, Count = Convert.ToInt16(images.Count) }.Save(writer); // The offset of the first icon. var offset = Marshal.SizeOf(typeof(IconHeader)) + images.Count * Marshal.SizeOf(typeof(IconEntry)); // Write all the icon entries for (var i = 0; i < images.Count; i++) { ImageConverter a = new ImageConverter(); Bitmap image = images[i] as Bitmap; byte[] data = (byte[])a.ConvertTo(image, typeof(byte[])); // var lol = new ImageMagick.MagickReadSettings() {Format=ImageMagick.MagickFormat.Png }; // ImageMagick.MagickImage mi = new ImageMagick.MagickImage(data1, lol); // byte[] data = mi.ToByteArray(); var entry = new IconEntry { Width = image.Width < 256 ? Convert.ToByte(image.Width) : (byte)0, Height = image.Height < 256 ? Convert.ToByte(image.Height) : (byte)0, ColorCount = 0, Reserved = 0, Planes = 1, BitCount = 32, BytesInRes = data.Length, ImageOffset = offset }; imageData[entry] = data; Console.WriteLine(entry); entry.Save(writer); offset += data.Length; } // Write the Icons. foreach (var kvp in imageData) { writer.Seek(kvp.Key.ImageOffset, SeekOrigin.Begin); writer.Write(kvp.Value); } } }
private static IconData BuildIconData(Stream source, IconHeader header, IconEntry entry) { using (var stream = new MemoryStream()) { using (var writer = new BinaryWriter(stream, System.Text.Encoding.UTF8, true)) { /* I’m not recreating an icon file here, just one icon at a time in the icon file format. * Therefore write the count as 1, and the offset as sizeof(header) + sizeof(entry). */ const short number = 1; var offset = Marshal.SizeOf(typeof(IconHeader)) + Marshal.SizeOf(typeof(IconEntry)); writer.Write(header.Reserved); writer.Write(header.Type); writer.Write(number); writer.Write((byte)entry.Width); writer.Write((byte)entry.Height); writer.Write(entry.ColorCount); writer.Write(entry.Reserved); writer.Write(entry.Planes); writer.Write(entry.BitCount); writer.Write(entry.BytesInRes); writer.Write(offset); var buffer = new byte[entry.BytesInRes]; source.Position = entry.ImageOffset; source.Read(buffer, 0, entry.BytesInRes); writer.Write(buffer); /* While this shouldn’t always be necessary, the managed Icon type will throw an exception when, for example, * trying to create an icon from any .png image that was just loaded from the file, whether it is 256×256 * (0x0 in the entry), or smaller, whereas this way always seems to work. */ using (var image = Image.FromStream(stream) as Bitmap) { Icon temp = null; try { temp = Icon.FromHandle(image.GetHicon()); /* Use the dimensions we got from the GDI icon, so we * don’t have to worry about double-height bitmaps etc.*/ return(new IconData { Icon = new Icon(temp, temp.Width, temp.Height), BitDepth = entry.BitCount }); } finally { if (temp != null) { NativeMethods.DestroyIcon(temp.Handle); } } } } } }
private static IEnumerable <IIconData> ReadStream(Stream stream) { using (var reader = new BinaryReader(stream, System.Text.Encoding.UTF8, true)) { var header = new IconHeader(reader); var entries = new IconEntry[header.Count]; for (var i = 0; i < header.Count; i++) { entries[i] = new IconEntry(reader); } var imageData = new IconData[header.Count]; for (var i = 0; i < header.Count; i++) { try { imageData[i] = BuildIconData(stream, header, entries[i]); } catch { } } /* Sort the results; by bit-depth, then size; descending, so that the * first icon found will be the largest resolution and highest bit depth. */ var bitDepths = imageData.Select(b => b.BitDepth).Distinct().ToList(); bitDepths.Sort(); var result = new List <IIconData>(); foreach (var i in bitDepths) { result.AddRange(imageData.Where(b => b.BitDepth == i).OrderBy(b => b.Icon.Width)); } result.Reverse(); return(result); } }