WPF支持GIF的各種方法


2012.12.18更新:修復下載鏈接

 

 

已知WPF的Image元素只能顯示GIF圖片的第一幀,而MediaElement不能加載作為資源或內嵌的資源的GIF圖片,所以網上有幾種實現方法。

我抄襲網上提供的方法,改頭換面后作為自己的GifImage實現。本文的前半部分介紹我的GifImage實現;后半部分做實驗,將我的GifImage和網上現存的幾種Gif支持方法做性能上的比較。

GifImage

我抄襲了這些地方提供的代碼:

GifImage繼承自FrameworkElement,添加了Source、Stretch、StretchDirection依賴項屬性,用法就跟標准Image元素差不多。從GIF里分解出各幀及其延續時間后,我在OnRender里自行繪制,並啟動DispatcherTimer計時,以便按時繪制下一幀。

解析GIF需要GifFormat類的幫助。GifFormat的構造函數需要Stream對象,構造函數認為從該Stream對象中可以讀到gif文件,然后按字節解析。

GIF圖片是由很多幀構成的,每一幀有延續時間、處置方法、左邊、上邊等屬性,當然還有最重要的圖像數據。GifFrame類就代表GIF圖片里的幀。

經GifFormat解析后的數據可由LogicalScreenWidth、LogicalScreenHeight和GetFrames方法獲得。

每當設置Source屬性,如果是gif圖片,就會重新創建一個新的GifFormat,然后啟動timer。

當然,Source URI的方案是多種多樣的,GifImage支持http、ftp、file、pack。

顯示GIF的兩個重點在MeasureOverride和OnRender方法,它們考慮了Stretch、StretchDirection、Width、Height等屬性。

比較

周銀輝的GifImageLib提供對GIF圖片的支持。他的GifImage的繼承鏈是FrameworkElement <-Control <-ContentControl <-UserControl<-GifImage。他的GifImage內含Canvas,Canvas內含N個Image,每個Image顯示GIF圖片的一幀。(N等於GIF圖片的幀數)設置GifImage.Source來顯示GIF圖片。

asprodotru的WpfAnimatedControl中的AnimatedImage是用來顯示gif圖片的。它繼承自Image元素,通過按時改變Image.Source以實現動畫效果。(GIF里的有些幀需要與前一幀疊加才能顯示出正確的影像,我不知道他只設置Image.Source為單一幀怎么保證正確顯示的,我還沒完全看懂。)設置AnimatedBitmap或調用LoadSmile方法來顯示圖片。

測試配置

測試用兩幅gif圖片,如下。

wrong.gif,19.3KB

oh.gif,51.2KB

 

代碼如下

 

[html]  view plain copy
 
  1. <Window xmlns:my="clr-namespace:Gqqnbig.Windows.Controls;assembly=GifImage"  x:Class="WpfApplication2.MainWindow"  
  2.         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"  
  3.         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"  
  4.         Title="MainWindow" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"   
  5.         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignHeight="187" d:DesignWidth="349">  
  6.     <Viewbox>  
  7.         <UniformGrid Columns="10" Name="grid"/>  
  8.     </Viewbox>  
  9. </Window>  

 

[csharp]  view plain copy
 
  1. public partial class MainWindow : Window  
  2. {  
  3.     public MainWindow()  
  4.     {  
  5.         InitializeComponent();  
  6.   
  7.         for (int i = 0; i < 100; i++)  
  8.         {  
  9.             //Gqqnbig.Windows.Controls.GifImage image = new Gqqnbig.Windows.Controls.GifImage();  
  10.             //image.Source = "pack://Application:,,,/OH.gif";  
  11.             //grid.Children.Add(image);  
  12.   
  13.             //GifImageLib.GifImage image = new GifImageLib.GifImage();  
  14.             //image.Source = "pack://Application:,,,/OH.gif";  
  15.             //grid.Children.Add(image);  
  16.   
  17.             //WpfAnimatedControl.AnimatedImage image = new WpfAnimatedControl.AnimatedImage();  
  18.             //var im = System.Drawing.Bitmap.FromFile("OH.gif");  
  19.             //image.LoadSmile((System.Drawing.Bitmap)im);  
  20.             //grid.Children.Add(image);  
  21.   
  22.               
  23.         }  
  24.     }  
  25. }  

 

 

取樣方法

兩幅gif圖片都進行測試。

運行后,每分鍾記錄一次CPU占用率、private bytes[1]、working set[2]的大小。共記錄三次。

測試結果

 

  我的GifImage GifImageLib AnimatedControl
  CPU Private bytes Working set CPU Private bytes Working set CPU Private bytes Working set
第一次測量 9 95136 80768 11 94780 82096 3 100248 94428
第二次測量 2 94320 80767 2 93568 82000 3 100224 94420
第三次測量 6 93952 80492 3 94576 82036 0 100116 94416
平均 5.67 94469.33 80675.67 5.33 94308.00 82044.00 2.00 100196.00 94421.33

使用wrong.gif

 

 

 

 

  我的GifImage GifImageLib AnimatedControl
  CPU Private bytes Working set CPU Private bytes Working set CPU Private bytes Working set
第一次測量 6 110792 102612 0 110520 103032 3 244320 237968
第二次測量 3 109188 102100 8 109772 103328 3 245356 238148
第三次測量 4 109132 102088 7 109664 103280 3 247668 238524
平均 4.33 109704.00 102266.67 5.00 109985.33 103213.33 3.00 245781.33 238213.33

使用oh.gif

 

結論

從CPU占用率來看,我的實現和周銀輝的實現不分仲伯;而通過改變Image.Source的AnimatedControl效率最高,應該得益於WPF的內部優化。

從Working set(工作集)來看,我的實現略優於周銀輝的GifImageLib;AnimatedControl則大很多,在第二次實驗時竟然是另兩者的兩倍還多。

下載代碼

代碼包括測試代碼、我的Gifimage、GifImageLib、AnimatedControl。測試代碼版權沒有,GifImageLib版權參考http://www.cnblogs.com/zhouyinhui/archive/2007/12/23/1011555.html,AnimatedControl版權是CPOL

地址:https://www.box.com/files#/files/0/f/66672665/1/f_5203962625

 

愛讓一切都對了

本文(不含程序代碼)以3.0協議發布

 


[1] Working Set看成一個進程可以用到(但不一定會使用)的物理內存。即不引起page fault異常就能夠訪問的內存。 Working Set包含了可能被其他程序共享的內存, 例如DLL就是一個典型的可能被其他程序共享的資源。所以所有進程的Working Set加起來有可能大於實際的物理內存。

[2] Private Bytes是只被本進程用占用的虛擬地址空間,不包括其他進程共享的內存。Private Bytes既包括不引起page fault異常就能夠訪問的內存也包括引起page fault異常才能夠訪問的內存。所以一般Private Bytes大於Working Set。但是如果一個進程和其他進程共享較多內存,也可能造成Working Set大於Private Bytes。(摘自http://blog.csdn.net/fw0124/article/details/6367360

 

from:http://blog.csdn.net/gqqnb/article/details/7213449


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM