八、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保留。必須爲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 之後,就不怕縮放問題了:
3、音量合成器的 Icon
沉積在可以放大圖標的喜悅中之後,在給程序加聲音的工作中,突然發現了個奇葩的東西:
我去~這是個什麼鬼,在網上沒查到是什麼原因,我真是不知道怎麼來描述這個問題……不過可以肯定是出在大分辨率的 Icon 上,既然這樣,就再增加小分辨率的 Icon 進去。
實驗發現,增加48*48大小的 Icon 就可以恢復正常了,如圖:
4、IcoFX
IcoFX 確實是款不錯的 Ico 文件編輯工具,上面的例子我也是用了這個軟件編輯的 Ico,相比 visual studio 中的圖像編輯器,IcoFX 操作更方便些,感興趣的同學可以下載學習一下,軟件有試用期,但是畢竟有註冊機之類的神器啊,百度一下就可以了。