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); } }