http://www.silverlightchina.net/html/study/WPF/2011/0824/9965.html

在我们寻求帮助的时候,最不愿意听到的答复是:很抱歉,在当前版本的产品中还没有实现该功能...
在WPF中显示动态的GIF图像时便遇到了这样的问题,WPF中强大的Image控件却不支持动态的GIF(其只能显示第一帧).当然,我们可以说WPF强大的动画能力,让我们完全有理由抛弃传统的GIF动画,但如某种情况下如果你觉得使用动态的GIF更合适的话(比如QQ表情,因为GIF是利于保存和传输的),没关系,本篇随笔将帮助你解决这个问题.

  1,曾有过的尝试:

  我们在实际开发过程中也遇到显示动态GIF的问题.发现普通的Image控件不能正常显示后,我们又发现网页浏览器却是可以的,以及windows
XP的"图片和传真查看器"也可以,但"Window
Live照片库"却不可以.所以我们最初打算使用通过包装WebBrowseControl来实现,即是在WPF中host一个.net2.0中的浏览器控件,然后让该浏览器来实现图片,成功了,但麻烦的事情是鼠标右键可以点出网页的上下文菜单.我们放弃了该方案,除了不愿意花时间来屏蔽上下文菜单和浏览器控件的多余功能外,同时我们的觉得浏览器控件过于"重量级",有点杀鸡用牛刀的感觉.另外,你可能会想到使用WPF中的Frame控件,但也会得到上述结果.另外,有网友说可以使用MediaElement控件,但大都没有成功,我也没有(可能是RP不够哈,呵呵...)

  2,GifBitmapDecoder

  我们发现WPF中有一个名为GifBitmapDecoder的类,其可以将动态GIF分解成很多帧并保存在一个列表中,每一帧为一个BitmapFrame类型的对象,其父类为BitmapSource,这也就意味着,我们可以将每一帧赋值给一个Image控件的Source属性,这样我们可以得到针对GIF各帧的Image系列:

GifBitmapDecoder decoder = new GifBitmapDecoder(
                           new Uri("OH.gif", UriKind.Relative),
                           BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);

foreach (BitmapFrame f in decoder.Frames)
            {
                Image image = new Image();
                image.Source = f;
                this.panel1.Children.Add(image);
            }

  下图为将一个GIF图片的12帧分解出来的所得到的一个系列图:

  

  不过先别高兴,这还不足以解决我们的问题,因为我们不知道每一帧显示的时间(帧与帧之间切换的时间间隔),以及一帧显示结束后它的处理方法(是显示下一帧吗?是显示背景色吗?等等...)所以我们还必须一个字节一个字节的解析GIF文件以便得到足够多的信息.

  3,解析GIF

  要解析文件就必须知道文件的存储结构,关于动态GIF的文件存储结构,可以参考这里:http://blog.zhongmoo.cn/post/45.html

  比如,得到帧的显示时间的方法是这样的:

private int ParseGraphicControlExtension(byte[] gifData, int offset)
        {
            int returnOffset = offset;
            // Extension Block
            int length = gifData[offset + 2];
            returnOffset = offset + length + 2 + 1;

byte packedField = gifData[offset + 3];
            currentParseGifFrame.disposalMethod = (packedField & 0x1C) >> 2;

// Get DelayTime
            int delay = BitConverter.ToUInt16(gifData, offset + 4);
            currentParseGifFrame.delayTime = delay;
            while (gifData[returnOffset] != 0x00)
            {
                returnOffset = returnOffset + gifData[returnOffset] + 1;
            }

returnOffset++;

return returnOffset;
        }

  关于如何解析就不多介绍了,你只有了解其文件结构然后不断地移动读取游标和读取相应的字节就可以完成了.

  4,包装成控件

  我们想要的最佳效果是,打造一个GifImage控件,就跟Image控件差不多,只要我们指定它的Source属性,然后其就自动查找GIF文件并读取或下载,然后解析并显示.

  所以,我们将该控件分成了两个部分,一个部分负责将根据用户指定的Source属性查找并读取或从网络下载GIF到内存流,然后另外一部分负责将得到的内存流解析并显示出来.

  gif文件在哪里?这是一个必须考虑到的问题,控件用户指定的是一个绝对路径吗,还是一个相对路径,是本地文件还是内嵌的资源文件或者是网络上的文件.还有该文件一定支持GIF动画吗,还是只是一个普通的静态图片,所以负责读取文件到内存流的代码中应该有类似于下面的代码:

if (source.Trim().ToUpper().EndsWith(".GIF") || ForceGifAnim)
            {
                if (!uri.IsAbsoluteUri)
                {
                    
                    GetGifStreamFromPack(uri);
                }
                else
                {

string leftPart = uri.GetLeftPart(UriPartial.Scheme);

if (leftPart == "http://" || leftPart == "ftp://" || leftPart == "file://")
                    {
                        
                        GetGifStreamFromHttp(uri);
                    }
                    else if (leftPart == "pack://")
                    {
                         
                        GetGifStreamFromPack(uri);
                    }
                    else
                    {
                        //创建无动画的普通Image
                        CreateNonGifAnimationImage();
                    }
                }
            }
            else
            {
                //创建无动画的普通Image
                CreateNonGifAnimationImage();
            }
        }

  当读取文件成功后,一切都好办了,通过解析内存流中的数据,我们可以得到足够多的信息,比如帧的列表,每帧显示的时间以及该帧显示完成后如何处理,那么我们就可以用一个计时器(DispatcherTimer)来处理这一切而形成一个动画了.

/**//// <summary>
        /// 从内存流中创建图片
        /// </summary>
        public void CreateGifAnimation(MemoryStream memoryStream)
        {
            Reset();

byte[] gifData = memoryStream.GetBuffer();

GifBitmapDecoder decoder = new GifBitmapDecoder(memoryStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);

numberOfFrames = decoder.Frames.Count;

try
            {
                ParseGif(gifData);
            }
            catch
            {
                throw new FileFormatException("Unable to parse Gif file format.");
            }

for (int i = 0; i < decoder.Frames.Count; i++)
            {
                frameList[i].Source = decoder.Frames[i];
                frameList[i].Visibility = Visibility.Hidden;
                canvas.Children.Add(frameList[i]);
                Canvas.SetLeft(frameList[i], frameList[i].left);
                Canvas.SetTop(frameList[i], frameList[i].top);
                Canvas.SetZIndex(frameList[i], i);
            }
            canvas.Height = logicalHeight;
            canvas.Width = logicalWidth;

frameList[0].Visibility = Visibility.Visible;

for (int i = 0; i < frameList.Count; i++)
            {
                Console.WriteLine(frameList[i].disposalMethod.ToString() + " " + frameList[i].width.ToString() + " " + frameList[i].delayTime.ToString());
            }

if (frameList.Count > 1)
            {
                if (numberOfLoops == -1)
                {
                    numberOfLoops = 1;
                }
                frameTimer = new System.Windows.Threading.DispatcherTimer();
                frameTimer.Tick += NextFrame;
                frameTimer.Interval = new TimeSpan(0, 0, 0, 0, frameList[0].delayTime * 10);
                frameTimer.Start();
            }
        }

  OK,我们可以像使用Image控件一样来使用我们的GifImage控件了:

  

源码下载

本文来自周银辉的博客,原文地址:http://www.cnblogs.com/zhouyinhui/archive/2007/12/23/1011555.html

在WPF中显示动态GIF(转)相关推荐

  1. WPF中显示GIF图片

    WPF中显示GIF图片: WPF很强大,但是他的Image控件却不支持GIF图片,只能显示第一帧.那么如何来显示GIF图片呢?以下有四种方法: 一. 第一种方法:使用MediaElement(实例中页 ...

  2. java jframe显示图片_java怎么在JFrame中显示动态图片

    java怎么在JFrame中显示动态图片 (2012-09-16 23:39:54) 标签: 杂谈 import java.awt.Graphics; import javax.swing.Image ...

  3. wpf时间显示代码_如何在ASP.NET和WPF中显示QR代码

    wpf时间显示代码 I've half-jokingly said that there's never a good reason to use a QR Code. However, I'm wo ...

  4. Android中显示动态图片

    通过Gifview.jar来实现Android应用中显示动态图片 效果图: 1.下载Gifview.jar  下载地址:http://download.csdn.net/detail/qq_26650 ...

  5. 水晶报表中显示动态图片

    href="file:///C:/WINDOWS/TEMP/msoclip1/01/clip_filelist.xml" rel="File-List" /&g ...

  6. WPF中显示GIF动态图

    开发工具与关键技术:Visual Studio 今天用WPF做一个登录页面,用到了GIF图,然后像引用图片的方式引用GIF图: 发现GIF跟图片没区别,只显示出来没有动态的GIF图,然后又陆续试了一些 ...

  7. 在JSP页面中显示动态时间

    源地址:http://blog.csdn.net/aitcax/article/details/41285305 静态时间: 1.页面首部添加 <%@page import="java ...

  8. wpf 加载html页面,使用MVVM在WPF中显示HTML

    我将 HTML-Source字符串保存在HTMLReport字段中称为"Report"的sql Server表中(字段类型为NTEXT).现在我需要显示存储的HTML 进入WPF窗 ...

  9. java中显示动态信息的方法_java里的动态表单技术

    最近的一个项目,由于客户的需求等信息不确定,为了降低以后修改的成本及产品的推广考虑到动态表单技术,之前也一直在考虑到动态表单技术,毕竟在delphi里已经实现过了,由于我们采用的hibernate的执 ...

最新文章

  1. 解决:“Word遇到问题需要关闭。我们对此引起的不便表示抱歉” 的问题
  2. 2020年高等数学方法与提高(上海理工大学)学习笔记:一元函数微分学
  3. 兼容浏览器将NodeList对象转换为数组
  4. java第五周课后作业
  5. spring-data-slor 通配符的匹配很全面, 但无法找到元素 'solr:solr-server' 的声明。
  6. 简单的linux下docker的下载与安装
  7. riso1855使用说明_理想CV1855驱动下载 理想CV1855打印机驱动 v20170627 32bit+64bit 免费安装版 下载-脚本之家...
  8. 数字信号处理笔记02:离散时间傅里叶变换(DTFT)
  9. html添加B站视频,iframe嵌入BiliBili视频方法B站视频外链
  10. 谷歌google搜索打不开、谷歌gmail邮箱及相关服务无法登录的解决的方法
  11. 最全的关于硬件测试的解读
  12. 用html和css轻松实现康奈尔笔记(5R笔记)模板
  13. How to become a hacker 译文(如何成为一名黑客)
  14. 用java实现生成12位的随机纯数字且首位不能为0
  15. 还在用网易云音乐客户端?out了~
  16. 使用bootstrap制作简单的左侧导航栏
  17. 专访实在智能孙林君:颠覆传统RPA的实在IPA模式,如何做到真正人人可用?
  18. static 的用法
  19. php7安装flarum,如何在Ubuntu 18.04上安装Flarum社区软件
  20. 使用NDB调试Linux字符设备

热门文章

  1. 根据pid判断某个进程是否存在
  2. HTTP详解-工作原理
  3. 云程序备援--CAP
  4. Production Hair Rendering in RenderMan
  5. Print out Android kernel log
  6. React Native 轻松集成分享功能(Android 篇)
  7. 坚持跑步与读书,方不辜负此生
  8. 背包类树形DP 选课题解
  9. Eclipse 中 Maven 项目默认JDK版本为1.5 的解决方法
  10. 版本控制工具——Git常用操作(下)