WPF支持GIF的各种方法
2012.12.18更新:修复下载链接
已知WPF的Image元素只能显示GIF图片的第一帧,而MediaElement不能加载作为资源或内嵌的资源的GIF图片,所以网上有几种实现方法。
我抄袭网上提供的方法,改头换面后作为自己的GifImage实现。本文的前半部分介绍我的GifImage实现;后半部分做实验,将我的GifImage和网上现存的几种Gif支持方法做性能上的比较。
GifImage
我抄袭了这些地方提供的代码:
- http://www.cnblogs.com/zhouyinhui/archive/2007/12/23/1011555.html 作者周银辉
 - http://www.codeproject.com/Articles/71891/WPF-GIF-Animation 作者asprodotru
 
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
代码如下
- <Window xmlns:my="clr-namespace:Gqqnbig.Windows.Controls;assembly=GifImage" x:Class="WpfApplication2.MainWindow"
 - xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 - xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 - Title="MainWindow" mc:Ignorable="d" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 - xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" d:DesignHeight="187" d:DesignWidth="349">
 - <Viewbox>
 - <UniformGrid Columns="10" Name="grid"/>
 - </Viewbox>
 - </Window>
 
- public partial class MainWindow : Window
 - {
 - public MainWindow()
 - {
 - InitializeComponent();
 - for (int i = 0; i < 100; i++)
 - {
 - //Gqqnbig.Windows.Controls.GifImage image = new Gqqnbig.Windows.Controls.GifImage();
 - //image.Source = "pack://Application:,,,/OH.gif";
 - //grid.Children.Add(image);
 - //GifImageLib.GifImage image = new GifImageLib.GifImage();
 - //image.Source = "pack://Application:,,,/OH.gif";
 - //grid.Children.Add(image);
 - //WpfAnimatedControl.AnimatedImage image = new WpfAnimatedControl.AnimatedImage();
 - //var im = System.Drawing.Bitmap.FromFile("OH.gif");
 - //image.LoadSmile((System.Drawing.Bitmap)im);
 - //grid.Children.Add(image);
 - }
 - }
 - }
 
取样方法
两幅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
WPF支持GIF的各种方法的更多相关文章
- WPF文字描边的解决方法(二)——支持文字竖排和字符间距调整
		
原文:WPF文字描边的解决方法(二)--支持文字竖排和字符间距调整 自前天格式化文本效果出来后,今天又添加文本竖排和调整字符间距的功能.另外,由于上次仓促,没来得及做有些功能的设计时支持,这次也调整好 ...
 - 使 WPF 支持触摸板的横向滚动
		
微软终于开始学苹果一样好好做触摸板了(就是键盘空格键下面那一大块).然而鉴于以前没有好好做,以至于 WPF 程序甚至都没有对触摸板的横向滚动提供支持(竖向滚动是直接使用了 MouseWheel,汗-- ...
 - WPF 支持的多线程 UI 并不是线程安全的
		
原文:WPF 支持的多线程 UI 并不是线程安全的 版权声明:本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可.欢迎转载.使用.重新发布,但务必保留文章署名吕毅(包含链 ...
 - 终于解决了IE8不支持数组的indexOf方法,array的IndexOf方法
		
/* 终于解决了IE8不支持数组的indexOf方法 */ if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (el ...
 - js错误:对象不支持此属性或方法
		
对象不支持此属性或方法 错误原因: 可能是js的文件名和另外一个文件重复. 也有可能是js里的function和另外一个function名字重复. 也有可能是js里的function和页面的某一元素重 ...
 - 对象不支持“attachEvent”属性或方法的解决办法
		
有些脚本在IE11下执行会报错误: 对象不支持“attachEvent”属性或方法 解决办法 解决办法:把attachEvent改为addEventListener即可
 - 让IE浏览器支持CSS3圆角的方法
		
如果要想在IE浏览器中实现圆角的效果,我们一般都会采用圆角图片的方式.用图片的话,基本就跟浏览器没有多大关系了,因为任何浏览器都支持这种方式.今天我们主要是讲解如果用CSS3样式表来实现圆角效果,值得 ...
 - 解决 IE 不支持 document.getElementsByClassName() 的方法
		
//create method getElementsByClassName for document if(!document.getElementsByClassName){ document.g ...
 - 解决IE10以下对象不支持“bind”属性或方法
		
IE10一下的浏览器,如果在JS代码中用了bind函数,那么就会报“SCRIPT438: 对象不支持“bind”属性或方法” 因为浏览器没有提供这个参数的方法,所以我们就自己写一个bind,来让这个参 ...
 
随机推荐
- go语言入门(三)
			
条件语句 go语言的条件语句结构如下: go语言的条件语句和其他语言类似.简单列举下: 1.if 语句,布尔表达式不需要括号 if 布尔表达式 { /* 在布尔表达式为 true 时执行 */ } 2 ...
 - 【摘要】JavaScript 的性能优化:加载和执行
			
1.浏览器遇到js代码会暂停页面的下载和渲染,谁晓得js代码会不会把html给强奸(改变)了: 2.延迟脚本加载:defer 属性 <html> <head> <titl ...
 - windows 下 nginx 配置虚拟主机
			
1. 在 nginx 的配置文件 nginx.conf 里面 引入虚拟主机配置文件,以后所有的虚拟主机配置文件都在写这个文件里 include vhost.conf; (或者新建vhost ...
 - 洛谷P1482 Cantor表(升级版) 题解
			
题目传送门 此题zha一看非常简单. 再一看特别简单. 最后瞟一眼,还是很简单. 所以在此就唠一下GCD大法吧: int gcd(int x,int y){ if(x<y) return gcd ...
 - beautifulsoup简单用法
			
原文地址 http://www.cnblogs.com/yupeng/p/3362031.html 这篇文章讲的也很全 http://www.cnblogs.com/twinsclover/archi ...
 - c++ primer 4 数组和指针
			
类比的思想学习数组和指针,c++提供类似于vector和迭代器的低级复合类型——数组和指针.与vector相似,数组可以保存某一种类型的一组对象:而他们的区别在于,数组的长度固定,数组一经创建就不允许 ...
 - ubuntu访问win10下的磁盘
			
在ubuntu下访问win10的磁盘时,提示出错. 先用命令查看一下磁盘挂载情况. sudo fdisk -l 会看到一些信息 我要访问的是E盘,也就是 /dev/sda6 这个分区 使用命令ntfx ...
 - lr11 controller打开提示cannot initialize driver dll,exiting
			
解决:在win7要以管理员身份运行才行的 问题2:在使用loadrunner时,从vuser generator启动controller的时候可能出现:由于另一个程序正在运行中 此操作无法完成.请选择 ...
 - LeetCode 137. Single Number II(只出现一次的数字 II)
			
LeetCode 137. Single Number II(只出现一次的数字 II)
 - CyclicBarrier 简介
			
CyclicBarrier 简介 CyclicBarrier 的字面意思是可循环使用(Cyclic)的屏障(Barrier). 它要做的事情是,让一组线程到达一个屏障(也可以叫同步点)时被阻塞,直到最 ...