I had a situation recently where I needed to add icons to a .NET context menu (attached to a system tray icon). Each icon had 20+ “images” inside it for the different resolutions and color depths. This class will allow you to view each of the inner icons for each icon in an icon (how is that for confusing).
Let me mention that the basis for this code was written by Matthew Hazlett (http://www.codeproject.com/dotnet/MultiIcon.asp) but has been modified to improve its structure. (No more storing MemoryStreams globally and now fits my coding standards for nameing for example.)
Code:
using System;
using System.IO;
using System.Collections.Generic;
using System.Drawing;
namespace ProductNamespace
{
class IconManager
{
private IconHeader _IconHeader;
private List<IconEntry> _InnerIcons;
private byte[] _IconData;
///
/// Gets all the icon information entries.
///
/// The icons.
public IconEntry[] Icons
{
get { return _InnerIcons.ToArray(); }
}
///
/// Gets the count of icon entries.
///
/// The count.
public int Count
{
get { return _InnerIcons.Count; }
}
///
/// Initializes a new instance of the class.
///
///
The filename of the icon to load.
public IconManager(string filename)
: this ()
{
using (FileStream IconFile = new FileStream(filename, FileMode.Open, FileAccess.Read))
{
_IconData = new byte[IconFile.Length];
IconFile.Read(_IconData, 0, (int)IconFile.Length);
}
LoadIcon(_IconData);
}
///
/// Initializes a new instance of the class.
///
///
The source icon to load.
public IconManager(Icon sourceIcon)
: this ()
{
using (MemoryStream IconStream = new MemoryStream())
{
sourceIcon.Save(IconStream);
_IconData = new byte[IconStream.Length];
IconStream.Position = 0;
IconStream.Read(_IconData, 0, (int)IconStream.Length);
}
LoadIcon(_IconData);
}
///
/// Initializes a new instance of the class.
///
private IconManager()
{
_InnerIcons = new List<IconEntry>();
_IconData = new byte[0];
}
///
/// Builds the icon.
///
///
The index.
///
public Icon BuildIcon(int index)
{
IconEntry thisIcon = _InnerIcons[index];
using (MemoryStream NewIconStream = new MemoryStream())
{
BinaryWriter writer = new BinaryWriter(NewIconStream);
// New Values
Int16 newNumber = 1;
Int32 newOffset = 22;
// Write it
writer.Write(_IconHeader.Reserved);
writer.Write(_IconHeader.Type);
writer.Write(newNumber);
writer.Write(thisIcon.Width);
writer.Write(thisIcon.Height);
writer.Write(thisIcon.ColorCount);
writer.Write(thisIcon.Reserved);
writer.Write(thisIcon.Planes);
writer.Write(thisIcon.BitCount);
writer.Write(thisIcon.BytesInRes);
writer.Write(newOffset);
// Grab the icon
byte[] tmpBuffer = new byte[thisIcon.BytesInRes];
using (MemoryStream IconStream = new MemoryStream(_IconData))
{
IconStream.Position = thisIcon.ImageOffset;
IconStream.Read(tmpBuffer, 0, thisIcon.BytesInRes);
}
writer.Write(tmpBuffer);
// Finish up
writer.Flush();
NewIconStream.Position = 0;
Icon NewIcon = new Icon(NewIconStream, thisIcon.Width, thisIcon.Height);
}
return NewIcon;
}
///
/// Finds the icon.
///
///
The width.
///
The height.
///
public Icon FindIcon(int width, int height)
{
int BestIconIndex = -1;
int BestIconColorDepth = 0;
for (int x = 0; x < _InnerIcons.Count; x++)
{
if (_InnerIcons[x].Width == width && _InnerIcons[x].Height == height)
{
if (BestIconColorDepth < _InnerIcons[x].BitCount)
{
BestIconIndex = x;
BestIconColorDepth = _InnerIcons[x].BitCount;
}
}
}
if (BestIconIndex == -1)
return null;
else
return BuildIcon(BestIconIndex);
}
///
/// Finds the icon.
///
///
The width.
///
The height.
///
The color depth.
///
public Icon FindIcon(int width, int height, int colorDepth)
{
for (int x = 0; x < _InnerIcons.Count; x++)
{
if (_InnerIcons[x].Width == width && _InnerIcons[x].Height == height)
{
if (colorDepth == _InnerIcons[x].BitCount)
return BuildIcon(x);
}
}
return null;
}
private void LoadIcon(byte[] iconData)
{
_IconData = iconData;
using (MemoryStream IconStream = new MemoryStream(_IconData))
{
_IconHeader = new IconHeader(IconStream);
// Read the icons
for (int counter = 0; counter < _IconHeader.Count; counter++)
{
IconEntry entry = new IconEntry(IconStream);
_InnerIcons.Add(entry);
}
}
}
#region Internal Classes
///
/// Stores the headers of the ICO
///
private class IconHeader
{
public Int16 Reserved;
public Int16 Type;
public Int16 Count;
///
/// Initializes a new instance of the class.
///
///
The ico stream.
public IconHeader(MemoryStream icoStream)
{
BinaryReader icoFile = new BinaryReader(icoStream);
Reserved = icoFile.ReadInt16();
Type = icoFile.ReadInt16();
Count = icoFile.ReadInt16();
}
}
///
/// Each icon if the file has its own header. This is where I read
/// the info for each icon.
///
public class IconEntry
{
public byte Width;
public byte Height;
public byte ColorCount;
public byte Reserved;
public Int16 Planes;
public Int16 BitCount;
public Int32 BytesInRes;
public Int32 ImageOffset;
///
/// Initializes a new instance of the class.
///
///
The ico stream.
public IconEntry(MemoryStream icoStream)
{
BinaryReader icoFile = new BinaryReader(icoStream);
Width = icoFile.ReadByte();
Height = icoFile.ReadByte();
ColorCount = icoFile.ReadByte();
Reserved = icoFile.ReadByte();
Planes = icoFile.ReadInt16();
BitCount = icoFile.ReadInt16();
BytesInRes = icoFile.ReadInt32();
ImageOffset = icoFile.ReadInt32();
}
}
#endregion
}
}