icons, string filepath)
{
using (var stream = new FileStream(filepath, FileMode.CreateNew, FileAccess.Write))
{
icons.Save(stream);
}
}
///
Saves the Windows icons to a single stream.
///
The list of icons.
///
The stream to save to.
public static void Save(this IList icons, Stream stream)
{
using (var writer = new BinaryWriter(stream))
{
long startposition = stream.Position;
var entries = new List();
var buffers = new List();
// create header.
var header = new MultiIconHeader()
{
Count = (short)icons.Count,
};
// create entries.
for (int i = 0; i < icons.Count; i++)
{
using (var icon_stream = new MemoryStream())
{
var entry = new MultiIconEntry();
var item = icons[i];
item.Save(icon_stream);
icon_stream.Position = 0;
using (var reader = new BinaryReader(icon_stream))
{
// icoHeader.Reserved[2],
// icoHeader.Type[2],
// none.Pos[2],
// Width[1],
// Height[1],
// ColorCount[1],
// Reserved[1]
// Planes[2]
// BitCount[2]
// BytesInRes[4]
// none.OffSet[4]
var header_reserved = reader.ReadInt16();
var header_type = reader.ReadInt16();
var none_startpos = reader.ReadInt16();
entry.Width = reader.ReadByte();
entry.Height = reader.ReadByte();
entry.ColorCount = reader.ReadByte();
entry.Reserved = reader.ReadByte();
entry.Planes = reader.ReadInt16();
entry.BitCount = reader.ReadInt16();
entry.BytesInRes = reader.ReadInt32();
entry.ImageOffset = MultiIconHeader.ByteSize + MultiIconEntry.ByteSize * icons.Count + buffers.Sum(buf => buf.Length);
var none_offset = reader.ReadInt32();
var buffer = new byte[icon_stream.Length - icon_stream.Position];
icon_stream.Read(buffer, 0, buffer.Length);
entries.Add(entry);
buffers.Add(buffer);
}
}
}
// Writer header.
writer.Write(header);
// Write entries.
foreach (var entry in entries)
{
writer.Write(entry);
}
// Write images.
foreach (var buffer in buffers)
{
writer.Write(buffer);
}
// Clear buffer and save.
writer.Flush();
}
}
///
Gets the smallest icon.
///
The list of icons.
/// The smallest icon.
public static Icon GetSmallest(this IEnumerable icons)
{
var icon =
(
from
item in icons
orderby
item.Width ascending
select
item
)
.FirstOrDefault();
return icon;
}
///
Gets the largest icon.
///
The list of icons.
/// The largest icon.
public static Icon GetLargest(this IEnumerable icons)
{
var icon =
(
from
item in icons
orderby
item.Width descending
select
item
)
.FirstOrDefault();
return icon;
}
}
///
Represents the header of a Windows (multi) icon.
internal class MultiIconHeader
{
///
The byte size of a single icon header.
public const int ByteSize = 2 + 2 + 2;
///
Initializes a new instance of the Tjip.Drawing.MultiIconHeader class.
public MultiIconHeader()
{
this.Type = 1;
}
public short Reserved { get; set; }
public short Type { get; set; }
public short Count { get; set; }
}
///
Extension methods for MultiIconHeader.
internal static class MultiIconHeaderExtensions
{
///
Reads a Windows (multi) icon header from the current stream
/// and advances the current position of the stream by six bytes.
///
///
The reader.
public static MultiIconHeader ReadMultiIconHeader(this BinaryReader reader)
{
var header = new MultiIconHeader()
{
Reserved = reader.ReadInt16(),
Type = reader.ReadInt16(),
Count = reader.ReadInt16(),
};
return header;
}
///
Writes a Windows (multi) icon header to the current stream
/// and advances the current position of the stream by six bytes.
///
///
The writer.
///
The Windows multi icon header to write.
public static void Write(this BinaryWriter writer, MultiIconHeader header)
{
writer.Write(header.Reserved);
writer.Write(header.Type);
writer.Write(header.Count);
}
}
///
Represents the entry of a Windows (multi) icon.
internal class MultiIconEntry
{
///
The byte size of a single icon entry.
public const int ByteSize = 1 + 1 + 1 + 1 + 2 + 2 + 4 + 4;
///
Initializes a new instance of the Tjip.Drawing.MultiIconEntry class.
public MultiIconEntry() { }
public byte Width { get; set; }
public byte Height { get; set; }
public byte ColorCount { get; set; }
public byte Reserved { get; set; }
public short Planes { get; set; }
public short BitCount { get; set; }
public int BytesInRes { get; set; }
public int ImageOffset { get; set; }
}
///
Extension methods for MultiIconEntry.
internal static class MultiIconEntryrExtensions
{
///
Reads a Windows (multi) icon entry from the current stream
/// and advances the current position of the stream by sixteen bytes.
///
///
The reader.
public static MultiIconEntry ReadMultiIconEntry(this BinaryReader reader)
{
var entry = new MultiIconEntry()
{
Width = reader.ReadByte(),
Height = reader.ReadByte(),
ColorCount = reader.ReadByte(),
Reserved = reader.ReadByte(),
Planes = reader.ReadInt16(),
BitCount = reader.ReadInt16(),
BytesInRes = reader.ReadInt32(),
ImageOffset = reader.ReadInt32(),
};
return entry;
}
///
Reads a Windows icon from the current stream
/// and advances the current position of the stream to the end of the
/// Windows icon in the stream.
///
///
The reader.
public static Icon ReadIcon(this BinaryReader reader, MultiIconHeader header, MultiIconEntry entry)
{
const short ICON_STREAM_START = 1;
const int ICON_STREAM_OFFSET = 22;
using (var newIcon = new MemoryStream())
{
using (var writer = new BinaryWriter(newIcon))
{
// Write it
writer.Write(header.Reserved);
writer.Write(header.Type);
writer.Write(ICON_STREAM_START);
writer.Write(entry.Width);
writer.Write(entry.Height);
writer.Write(entry.ColorCount);
writer.Write(entry.Reserved);
writer.Write(entry.Planes);
writer.Write(entry.BitCount);
writer.Write(entry.BytesInRes);
writer.Write(ICON_STREAM_OFFSET);
// Grab the icon
byte[] tmpBuffer = new byte[entry.BytesInRes];
reader.BaseStream.Position = entry.ImageOffset;
reader.Read(tmpBuffer, 0, entry.BytesInRes);
writer.Write(tmpBuffer);
// Finish up
writer.Flush();
newIcon.Position = 0;
return new Icon(newIcon);
}
}
}
///
Writes a Windows (multi) icon entry to the current stream
/// and advances the current position of the stream by sixteen bytes.
///
///
The writer.
///
The Windows multi icon entry to write.
public static void Write(this BinaryWriter writer, MultiIconEntry entry)
{
writer.Write(entry.Width);
writer.Write(entry.Height);
writer.Write(entry.ColorCount);
writer.Write(entry.Reserved);
writer.Write(entry.Planes);
writer.Write(entry.BitCount);
writer.Write(entry.BytesInRes);
writer.Write(entry.ImageOffset);
}
}
}[/code]
It works perfectly. The only thing I still need to solve is the conversion of PNG24 to ICO:
[code=c#]var icon = Icon.FromHandle(new Bitmap("some_pgn24.png").GetHicon());[/code]
This results in an icon that does not have an alpha-channel. When I solved this, I will inform you.