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

代码如下

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

取样方法

两幅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的各种方法的更多相关文章

  1. WPF文字描边的解决方法(二)——支持文字竖排和字符间距调整

    原文:WPF文字描边的解决方法(二)--支持文字竖排和字符间距调整 自前天格式化文本效果出来后,今天又添加文本竖排和调整字符间距的功能.另外,由于上次仓促,没来得及做有些功能的设计时支持,这次也调整好 ...

  2. 使 WPF 支持触摸板的横向滚动

    微软终于开始学苹果一样好好做触摸板了(就是键盘空格键下面那一大块).然而鉴于以前没有好好做,以至于 WPF 程序甚至都没有对触摸板的横向滚动提供支持(竖向滚动是直接使用了 MouseWheel,汗-- ...

  3. WPF 支持的多线程 UI 并不是线程安全的

    原文:WPF 支持的多线程 UI 并不是线程安全的 版权声明:本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可.欢迎转载.使用.重新发布,但务必保留文章署名吕毅(包含链 ...

  4. 终于解决了IE8不支持数组的indexOf方法,array的IndexOf方法

    /* 终于解决了IE8不支持数组的indexOf方法 */ if (!Array.prototype.indexOf) { Array.prototype.indexOf = function (el ...

  5. js错误:对象不支持此属性或方法

    对象不支持此属性或方法 错误原因: 可能是js的文件名和另外一个文件重复. 也有可能是js里的function和另外一个function名字重复. 也有可能是js里的function和页面的某一元素重 ...

  6. 对象不支持“attachEvent”属性或方法的解决办法

    有些脚本在IE11下执行会报错误: 对象不支持“attachEvent”属性或方法 解决办法 解决办法:把attachEvent改为addEventListener即可

  7. 让IE浏览器支持CSS3圆角的方法

    如果要想在IE浏览器中实现圆角的效果,我们一般都会采用圆角图片的方式.用图片的话,基本就跟浏览器没有多大关系了,因为任何浏览器都支持这种方式.今天我们主要是讲解如果用CSS3样式表来实现圆角效果,值得 ...

  8. 解决 IE 不支持 document.getElementsByClassName() 的方法

    //create method getElementsByClassName for document if(!document.getElementsByClassName){ document.g ...

  9. 解决IE10以下对象不支持“bind”属性或方法

    IE10一下的浏览器,如果在JS代码中用了bind函数,那么就会报“SCRIPT438: 对象不支持“bind”属性或方法” 因为浏览器没有提供这个参数的方法,所以我们就自己写一个bind,来让这个参 ...

随机推荐

  1. poj 2420(模拟退火)

    A Star not a Tree? Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6066   Accepted: 285 ...

  2. 洛谷 P1897电梯里的爱情 题解

    题目传送门 对于每个输入的第i个人,直接使用桶,但注意范围要开大一些. #include<bits/stdc++.h> using namespace std; ],x,sum,h,Max ...

  3. MVC – 9.mvc整体请求流程

    1.请求管道 2~5微软自己的验证,我们一般不用. 在全局配置文件中-已经配置一个路由过滤器-为第7个事件注册了路由方法 1.在application_start中向静态路由表注册了路由数据,在管道第 ...

  4. 专题-Delphi/C++ Builder多线程编程与调试

    [目录] Delphi.C++ Builder多线程程序编码调试的一点经验谈 多线程程序的填坑笔记和多线程编程应该遵循的规则(天地弦) 多线程编程中死锁问题的跟踪与解决 临界.多重读独占写多线程同步测 ...

  5. bzoj1941 hdu5992

    看了青岛赛区的题简单学了一下kd,感觉这东西还是挺厉害的 一般kd树找最近点对最坏是O(n),但是随机情况下跑得还是很快的 kd树是一棵BST,但是每一层的关键字不同 一般写法是按照每一维轮流来,这一 ...

  6. Python教程(一)Python简介

    Python就为我们提供了非常完善的基础代码库,覆盖了网络.文件.GUI.数据库.文本等大量内容,被形象地称作“内置电池(batteries included)”.用Python开发,许多功能不必从零 ...

  7. mp4文件数据格式解析

    unsigned int(32)[3]    32*3bit string[32]  32*8bit class VisualSampleEntry(codingname) extends Sampl ...

  8. Java 中可变参数

    可变参数 Java 中可变参数 现在需要编写一个求和的功能,但是不知道有几个参数,在调用的时候才知道有几个参数,请问这如何实现呢? Java 给我们提供了一个 JDK 1.5 的新特性---可变参数 ...

  9. 一道js试题

    直接上试题 <script type="text/javascript"> var output = '123js'; var object = { output : ...

  10. (总结)Nginx/LVS/HAProxy负载均衡软件的优缺点详解

    Nginx/LVS/HAProxy负载均衡软件的优缺点详解 PS:Nginx/LVS/HAProxy是目前使用最广泛的三种负载均衡软件,参考了一些资料,结合自己的一些使用经验,总结一下. 一般对负载均 ...