ico
格式是我们常见的一种图标格式,曾经常常通过一些别的软件进行转换,现在研究了一下C#其实也可以进行转换。
网上很多方法是通过Bitmap
直接获取句柄转为Icon
对象并保存,这样得到的ico
质量非常差。
左找右找发现可以直接读取图像全部信息,然后先写入ico
文件头,再填入图像信息,即可实现无损转换。
1,ico
图标文件结构
首先来看一下ico
文件的结构:
根据这个,我们可以使用C#中使用内存流和文件流将ico
文件的头信息和图像体组装起来,实现格式转换。
2,代码实现
为了保证ico
保留透明度且不失真,我们将图片读取为png
格式数据,再将数据写入目标文件。这里我写了个函数来实现图片转换ico
:
/// <summary>
/// ICON图标文件头模板
/// </summary>
private static readonly byte[] ICON_HEAD_TEMPLATE = {
0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x80,
0x80, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00,
0xC4, 0x6E, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00
};
/// <summary>
/// 图片转换为ico文件
/// </summary>
/// <param name="origin">原图片路径</param>
/// <param name="destination">输出ico文件路径</param>
/// <param name="iconSize">输出ico图标尺寸,不可大于255x255</param>
/// <returns>是否转换成功</returns>
public static bool ConvertImageToIcon(string origin, string destination, Size iconSize)
{
if (iconSize.Width > 255 || iconSize.Height > 255)
{
return false;
}
// 把原图并缩放到指定大小
Image originResized = new Bitmap(Image.FromFile(origin), iconSize);
// 存放缩放后的原图的内存流
MemoryStream originImageStream = new MemoryStream();
// 将缩放后的原图以png格式写入到内存流
originResized.Save(originImageStream, ImageFormat.Png);
// Icon的文件字节内容
List<byte> iconBytes = new List<byte>();
// 先加载Icon文件头
iconBytes.AddRange(ICON_HEAD_TEMPLATE);
// 文件头的第7和8位分别是图标的宽高,修改为设定值,不可大于255
iconBytes[6] = (byte)iconSize.Width;
iconBytes[7] = (byte)iconSize.Height;
// 文件头的第15到第18位是原图片内容部分大小
byte[] size = BitConverter.GetBytes((int)originImageStream.Length);
iconBytes[14] = size[0];
iconBytes[15] = size[1];
iconBytes[16] = size[2];
iconBytes[17] = size[3];
// 追加缩放后原图字节内容
iconBytes.AddRange(originImageStream.ToArray());
// 利用文件流保存为Icon文件
Stream iconFileStream = new FileStream(destination, FileMode.Create);
iconFileStream.Write(iconBytes.ToArray(), 0, iconBytes.Count);
// 关闭所有流并释放内存
iconFileStream.Close();
originImageStream.Close();
originResized.Dispose();
return File.Exists(destination);
}
大家可以对照上面的ico
格式解析图来看写入的文件头信息,以及修改了哪几个字节,就明白了。
调用函数即可实现转换,例如我这里转换输出一个128 x 128
的ico
文件:
bool saved = ConvertImageToIcon(@"C:\Users\swsk33\Pictures\头像与图标\38.jpg", @"E:\中转\icon.ico", new Size(128, 128));
Console.WriteLine("是否转换成功:" + (saved ? "是" : "否"));
可见这样,就实现了转换的功能: