C# Winform 窗体美化(八、Icon)

八、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 是这样的:

渣画质的 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保留。必须为0
            bin.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 文件中可以放不同分辨率的图像,只需要在文件中创建高分辨率的版本就可以了:

Icon 多分辨率

创建多个分辨率的 Icon 之后,就不怕缩放问题了:

Icon 高分辨率

3、音量合成器的 Icon

沉积在可以放大图标的喜悦中之后,在给程序加声音的工作中,突然发现了个奇葩的东西:

音量合成器中的 Icon

我去~这是个什么鬼,在网上没查到是什么原因,我真是不知道怎么来描述这个问题……不过可以肯定是出在大分辨率的 Icon 上,既然这样,就再增加小分辨率的 Icon 进去。

IcoFx 增加小分辨率的 Icon

实验发现,增加48*48大小的 Icon 就可以恢复正常了,如图:

正常的音量合成器

4、IcoFX

IcoFX 确实是款不错的 Ico 文件编辑工具,上面的例子我也是用了这个软件编辑的 Ico,相比 visual studio 中的图像编辑器,IcoFX 操作更方便些,感兴趣的同学可以下载学习一下,软件有试用期,但是毕竟有注册机之类的神器啊,百度一下就可以了。

猜你喜欢

转载自blog.csdn.net/myinc/article/details/70537011