C#实现把图片转换为ico格式

1,446 阅读2分钟

ico格式是我们常见的一种图标格式,曾经常常通过一些别的软件进行转换,现在研究了一下C#其实也可以进行转换。

网上很多方法是通过Bitmap直接获取句柄转为Icon对象并保存,这样得到的ico质量非常差。

左找右找发现可以直接读取图像全部信息,然后先写入ico文件头,再填入图像信息,即可实现无损转换

1,ico图标文件结构

首先来看一下ico文件的结构:

ico文件结构解析.png

根据这个,我们可以使用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 128ico文件:

bool saved = ConvertImageToIcon(@"C:\Users\swsk33\Pictures\头像与图标\38.jpg", @"E:\中转\icon.ico", new Size(128, 128));
Console.WriteLine("是否转换成功:" + (saved ? "是" : "否"));

可见这样,就实现了转换的功能:

image.png