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 操作更方便些,感興趣的同學可以下載學習一下,軟件有試用期,但是畢竟有註冊機之類的神器啊,百度一下就可以了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章