【2012.12.18更新】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


代码如下

<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]的大小。共记录三次。

测试结果

 我的GifImageGifImageLibAnimatedControl
 CPUPrivate bytesWorking setCPUPrivate bytesWorking setCPUPrivate bytesWorking set
第一次测量99513680768119478082096310024894428
第二次测量2943208076729356882000310022494420
第三次测量6939528049239457682036010011694416
平均5.6794469.3380675.675.3394308.0082044.002.00100196.0094421.33
使用wrong.gif



 我的GifImageGifImageLibAnimatedControl
 CPUPrivate bytesWorking setCPUPrivate bytesWorking setCPUPrivate bytesWorking set
第一次测量611079210261201105201030323244320237968
第二次测量310918810210081097721033283245356238148
第三次测量410913210208871096641032803247668238524
平均4.33109704.00102266.675.00109985.33103213.333.00245781.33238213.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

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值