八、Icon
之前 Winform 项目也有在 Icon 上遇到些问题(这里的 Icon 指的是 .ico 类型的文件),比如刚开始不知道怎么让自己的程序 Icon 和其他软件一样可以放大,还有放大之后在音量合成器中会出现比较奇葩的效果之类的问题,这里简单整理下,以后再有其他问题再补充。
1、C# 代码转换 Icon 格式
最开始写 Winform 程序的时候,程序图标都是从网上 down 的,因为那时候我下载了个精简版的ps cs3 里面不能保存 ico 文件,后来我找了个可以用 ps cs3 保存 ico 文件的插件,就可以保存 Ico 格式的文件了,最近突发奇想能不能用 C# 代码来转换 Icon 格式,这个例子在网上看过,有个网站可以将 Png 转换成 Ico,OK 既然有就可以试验一下。
网上最多的代码就是:
Bitmap iconBm = new Bitmap(oriImage, size);
Icon icon = Icon.FromHandle(iconBm.GetHicon());
//保存文件省略
这玩意儿确实能生成 Ico 格式的文件,但是这真的是个坑,因为生成的 Ico 是这样的:
网上有这种困扰的人很多,大致看了下原因是颜色位数的问题,那肯定的,颜色少的也太多了……
不过随后找到一个文章,完美的做好了转换,引用地址:http://www.cnblogs.com/ahdung/p/ConvertToIcon.html
Icon 文件说明:https://msdn.microsoft.com/en-us/library/ms997538.aspx
作者的方法原理是:先将image编码为png;再将png原样包装成一个icon。在这要谢谢作者提供的方法,提供了新思路,完美解决问题。
这里顺便一贴方法代码(Save 方法是我顺手补的……):
/// <summary>
/// 将 Image(PNG) 保存到指定目录文件名的 Icon
/// </summary>
/// <param name="image"></param>
/// <param name="file"></param>
/// <returns></returns>
public static bool Save(Image image, string file)
{if (image != null){using (Icon icon = ConvertToIcon(image)){try{FileStream fs = new FileStream(file, FileMode.Create, FileAccess.Write);icon.Save(fs);fs.Flush();fs.Close();fs.Dispose();return true;}catch { }}}return false;
}/// <summary>
/// 转换Image为Icon
/// </summary>
/// <param name="image">要转换为图标的Image对象</param>
/// <param name="nullTonull">当image为null时是否返回null。false则抛空引用异常</param>
/// <exception cref="ArgumentNullException" />
public static Icon ConvertToIcon(Image image, bool nullTonull = false)
{if (image == null){if (nullTonull) { return null; }throw new ArgumentNullException("image");}using (MemoryStream msImg = new MemoryStream(), msIco = new MemoryStream()){image.Save(msImg, ImageFormat.Png);using (var bin = new BinaryWriter(msIco)){//写图标头部bin.Write((short)0); //0-1保留bin.Write((short)1); //2-3文件类型。1=图标, 2=光标bin.Write((short)1); //4-5图像数量(图标可以包含多个图像)bin.Write((byte)image.Width); //6图标宽度bin.Write((byte)image.Height); //7图标高度bin.Write((byte)0); //8颜色数(若像素位深>=8,填0。这是显然的,达到8bpp的颜色数最少是256,byte不够表示)bin.Write((byte)0); //9保留。必须为0bin.Write((short)0); //10-11调色板bin.Write((short)32); //12-13位深bin.Write((int)msImg.Length); //14-17位图数据大小bin.Write(22); //18-21位图数据起始字节//写图像数据bin.Write(msImg.ToArray());bin.Flush();bin.Seek(0, SeekOrigin.Begin);return new Icon(msIco);}}
}
这个方法所转换的 Icon 是无损带透明的完美效果。
注:这里补充个小代码,是 OpenFileDialog 选择文件的:
OpenFileDialog 中可以设置 Filter 属性,默认不设置则可以选择所有文件,也可以限制只选自己需要的文件类型。
1. 限制一种文件类型:Filter=”照片|*.jpg”;
2. 限制同类多种文件类型:Filter=”照片|*.jpg;*jpeg;*png”;
3. 限制多种分类文件类型:Filter=”照片|.jpg;*jpeg;*png|音频|.mp3”;
代码如下:
//弹出打开图片对话框
OpenFileDialog fileDialog = new OpenFileDialog();
fileDialog.Filter = "图片文件|*.jpg;*.jpeg;*.png";
if (fileDialog.ShowDialog() == DialogResult.OK)
{//选择图片进行加载oriImagePath = fileDialog.FileName;
}
2、可放大的程序图标
用过 win7 的小伙伴大部分应该都知道的,按住 ctrl 键 + 鼠标滚轮 可以对程序图标放大缩小,但是固定尺寸的程序图标就不会跟着放大缩小,如图:
这种问题其实倒还是简单,因为 Icon 文件中可以放不同分辨率的图像,只需要在文件中创建高分辨率的版本就可以了:
创建多个分辨率的 Icon 之后,就不怕缩放问题了:
3、音量合成器的 Icon
沉积在可以放大图标的喜悦中之后,在给程序加声音的工作中,突然发现了个奇葩的东西:
我去~这是个什么鬼,在网上没查到是什么原因,我真是不知道怎么来描述这个问题……不过可以肯定是出在大分辨率的 Icon 上,既然这样,就再增加小分辨率的 Icon 进去。
实验发现,增加48*48大小的 Icon 就可以恢复正常了,如图:
4、IcoFX
IcoFX 确实是款不错的 Ico 文件编辑工具,上面的例子我也是用了这个软件编辑的 Ico,相比 visual studio 中的图像编辑器,IcoFX 操作更方便些,感兴趣的同学可以下载学习一下,软件有试用期,但是毕竟有注册机之类的神器啊,百度一下就可以了。