2016-10-10 45 views
1

我正在使用下面的代碼(基於我在另一個答案中找到的內容)將圖像(通常是添加到項目資源中的PNG)轉換爲表單標題等中使用的圖標。如何解決圖像轉換爲圖標?

public static Icon IconFromImage(Image img) 
{ 
    using (var bmp = new Bitmap(img)) 
    { 
     Byte[] ba; 
     using (var ms = new MemoryStream()) 
     { 
      bmp.Save(ms, ImageFormat.Png); 
      ms.Seek(0, SeekOrigin.Begin); 
      ba = ms.ToArray(); 
     } 

     using (var imgData = new MemoryStream()) 
     using (var writer = new BinaryWriter(imgData)) 
     { 
      if (writer != null) 
      { 
       //Header (6 bytes) 
       writer.Write((Byte)0);    // 0 reserved: set to 0 
       writer.Write((Byte)0);    // 1 reserved: set to 0 
       writer.Write((Int16)1);    // 2-3 image type: 1 = icon, 2 = cursor 
       writer.Write((Int16)1);    // 4-5 number of images 

       //Image entry #1 (16 bytes) 
       writer.Write((Byte)bmp.Width);  // 0 image width 
       writer.Write((Byte)bmp.Height);  // 1 image height 
       writer.Write((Byte)0);    // 2 number of colors 
       writer.Write((Byte)0);    // 3 reserved 
       writer.Write((Int16)0);    // 4-5 color planes 
       writer.Write((Int16)32);   // 6-7 bits per pixel 
       writer.Write(ba.Length);   // 8-11 size of image data 
       writer.Write(6 + 16);    // 12-15 offset to image data 

       //Write image data 
       writer.Write(ba);     // PNG data must contain the whole PNG data file! 

       writer.Flush(); 
       writer.Seek(0, SeekOrigin.Begin); 

       return new Icon(imgData,16,16); 
      } 
     } 
    } 
    return null; 
} 

從圖像到圖標工作正常。但有一種情況我需要抓取該表單的標題圖標並從中獲取圖像。當我爲標題圖像使用實際的基於文件的ICO文件時,這曾經工作,但現在我正在使用轉換代碼來獲取表單的圖標,所得到的PNG看起來很可怕。

窗體的標題圖標: :使用Bitmap.FromHicon(new Icon(theForm.Icon, new Size(16, 16)).Handle)呈現

enter image description here

圖片(注:以前使用theForm.Icon.ToBitmap(),但現在的錯誤)

enter image description here

我上閱讀評論另一篇文章中,一位用戶表示,如果使用PNG來導出圖標,那麼回到圖像將會很糟糕「,因爲PNG具有超過一點透明度「。如果那是我遇到的問題,那麼我能做些什麼呢?

+0

'var img = this.Icon.ToBitmap()'有什麼問題? –

+0

圖標沒有高質量的編碼器。 [從文件中提取圖標,然後保存爲透明度爲.ico文件](http://stackoverflow.com/a/37354129/1070452)可能會回答你的問題 – Plutonix

+0

@RezaAghaei該通用版本似乎不喜歡32bpp規範。如果我將'writer.Write((Int16)32)'更改爲24bpp,或者使用需要16x16大小的那個,那很好。我得到一個數組溢出異常。 – DonBoitnott

回答

1

您可以使用IconBitmapDecoder獲得圖標流保護像素格式,並使用PngBitmapEncoder保存在一個PNG圖像該流:

using System.Drawing; 
using System.Windows.Media.Imaging; 
class IconHelper 
{ 
    public static Bitmap PngFromIcon(Icon icon) 
    { 
     Bitmap png = null; 
     using (var iconStream = new System.IO.MemoryStream()) 
     { 
      icon.Save(iconStream); 
      var decoder = new IconBitmapDecoder(iconStream, 
       BitmapCreateOptions.PreservePixelFormat, 
       BitmapCacheOption.None); 

      using (var pngSteam = new System.IO.MemoryStream()) 
      { 
       var encoder = new PngBitmapEncoder(); 
       encoder.Frames.Add(decoder.Frames[0]); 
       encoder.Save(pngSteam); 
       png = (Bitmap)Bitmap.FromStream(pngSteam); 
      } 
     } 
     return png; 
    } 
} 

要使用這些類,您需要添加對PresentationCoreWindowsBaseSystem.Xaml的引用。那麼用法如下:

this.pictureBox1.Image = IconHelper.PngFromIcon(this.Icon); 

結果與您用來創建圖標的原始png相同。

+0

這個效果非常好,Reza。非常感謝你。順便說一句,我不必包含'System.Xaml'。 – DonBoitnott

+0

我在.NET 4.0上檢查它,我會用.NET 4.5檢查它。也許我錯了。 –

0

嘗試使用Bitmap.FromHicon(this.Icon.Handle),您可能會得到更好的結果。在至少ToBitmap()似乎BARF如果PNG有壓縮:Displaying an icon in a pictureboxhttp://community.sharpdevelop.net/forums/t/21851.aspx

+0

我認爲這與'theForm.Icon.ToBitmap()'基本相同,當我通過將編碼質量降低到24bpp來實現它時,它不會帶來更好的結果。 – DonBoitnott

+0

在這種情況下,我只是建議在表單上粘貼一個字段,以便攜帶原始位圖,以便您可以從此處取出:) – tolanj

+0

我希望它不會出現這種情況。不應該,因爲之前我使用「專業」圖標時工作。 – DonBoitnott