WPF 播放 gif


前言

本文告诉大家如何在 WPF 播放 Gif 图片,提供了几个方法进行播放,包括比较性能。
1.MediaElement 方法
2.GifBitmapDecoder 方法
3.Magick 方法
4.WinForm 的方法

MediaElement 方法

  • 这是比较不推荐的方法,但是使用简单
<MediaElement x:Name="gifMedia"  Source="x.gif" UnloadedBehavior="Manual"  LoadedBehavior="Play" />

GifBitmapDecoder 方法

  • 使用 GifBitmapDecoder 能用上 WIC 层系统解码,能支持很多奇怪的格式,以下是我实现的版本,我实现的版本只能播放简单的全画的 GIF 图片
    WPF 通过 GifBitmapDecoder 调用 WIC 解析 Gif 和进行动画播放的简单方法[1]

Magick 方法

  • 这个方法请参见博客 WPF一个性能比较好的gif解析库[2]

WinForm 的方法

  • 使用

  • 本文提供的类,可以直接在 Xaml 使用或者在 cs 使用,可以控制开始播放和停止。

  • 在播放的过程中,使用很少的内存。在使用到一定的时间,会自动释放内存。而且比我现在项目使用的播放的 CPU 要少很多,我自己写的 gif 播放需要使用 3% 左右的 CPU,下面这个类使用的 CPU 只有 1% 。当然我的 gif 解析使用的内存会比下面的代码少,不然我就不敢把下面的代码开源了

  • 在 xaml 使用的方法:

 <local:GifImageControl x:Name="Image" Path="2017年3月23日 115958.gif"></local:GifImageControl>
  • 在添加进之后就会自动开始播放
  • 如果需要在后台代码添加,那么可以使用下面代码
        <Grid x:Name="HlosqrrsDnqxv">
        </Grid>

            var image = new GifImageControl("2017年3月23日 115958.gif");
            HlosqrrsDnqxv.Children.Add(image);

  • 因为代码很简单,所以需要其他的功能,请看源代码

源码

  • 代码放在 Github ,可以直接复制这个类到工程使用。下面代码可以用在正式项目中。
    /// <summary>
    /// 使用 WinForm 播放 Gif 
    /// </summary>
    /// <example>
    /// xaml:
    /// <local:GifImageControl x:Name="Image" Path="lindexi.gif"></local:GifImageControl>
    /// cs:
    /// var image = new GifImageControl("E:\lindexi.gif");
    /// Grid.Children.Add(image);
    /// </example>
    public class GifImageControl : Image
    {
        /// <inheritdoc />
        public GifImageControl()
        {
        }

        /// <inheritdoc />
        public GifImageControl(string path)
        {
            Path = path;
        }

        /// <summary>
        ///     图片的地址
        /// </summary>
        public string Path
        {
            get => _path;
            set
            {
                if (!File.Exists(value))
                {
                    var file = new FileInfo(value);
                    if (!file.Exists)
                    {
                        throw new ArgumentException("找不到文件" + value);
                    }

                    value = file.FullName;
                }

                _path = value;
                Start();
            }
        }

        /// <summary>
        ///     播放图片
        /// </summary>
        public void Start()
        {
            if (_bitmap != null)
            {
                //多次点击播放,如果没有停止,会让上一个图片还在播放
                Stop();
            }

            var path = Path;
            _bitmap = (Bitmap) System.Drawing.Image.FromFile(path);
            ImageAnimator.Animate(_bitmap, OnFrameChanged);
            _bitmapSource = GetBitmapSource();
            Source = _bitmapSource;
        }

        /// <summary>
        ///     停止播放
        /// </summary>
        public void Stop()
        {
            if (_bitmap == null)
            {
                return;
            }

            ImageAnimator.StopAnimate(_bitmap, OnFrameChanged);
            _bitmap.Dispose();
            _bitmap = null;
        }

        private Bitmap _bitmap;

        private BitmapSource _bitmapSource;
        private string _path;


        private void OnFrameChanged(object sender, EventArgs e)
        {
            Dispatcher.InvokeAsync(OnFrameChangedInMainThread);
        }

        private void OnFrameChangedInMainThread()
        {
            ImageAnimator.UpdateFrames();

            _bitmapSource = GetBitmapSource();
            Source = _bitmapSource;
            InvalidateVisual();
        }

        private BitmapSource GetBitmapSource()
        {
            IntPtr inptr = _bitmap.GetHbitmap();
            _bitmapSource = Imaging.CreateBitmapSourceFromHBitmap(
                inptr, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
            DeleteObject(inptr);
            return _bitmapSource;
        }

        [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool DeleteObject(IntPtr hObject);
    }
  • 如果在运行项目出现 异常,那么请把 DeleteObject 方法修改为下面的代码
      [DllImport("gdi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool DeleteObject(IntPtr hObject);
  • 打开 .sln 文件,然后按 F5 运行,可以看到占用内存在 120M ,在运行一定时间,回收内存,占用内存70M,而CPU几乎都不需要。WPF播放GIF控件完整代码 – CSDN博客[3]
  • 如果在运行出现任何问题,请告诉我,上面这个方法不保证可以解决任何的gif图片。

参考资料

[1]

WPF 通过 GifBitmapDecoder 调用 WIC 解析 Gif 和进行动画播放的简单方法: https://blog.lindexi.com/post/WPF-%E9%80%9A%E8%BF%87-GifBitmapDecoder-%E8%B0%83%E7%94%A8-WIC-%E8%A7%A3%E6%9E%90-Gif-%E5%92%8C%E8%BF%9B%E8%A1%8C%E5%8A%A8%E7%94%BB%E6%92%AD%E6%94%BE%E7%9A%84%E7%AE%80%E5%8D%95%E6%96%B9%E6%B3%95.html

[2]

WPF一个性能比较好的gif解析库: https://lindexi.gitee.io/post/WPF-%E4%B8%80%E4%B8%AA%E6%80%A7%E8%83%BD%E6%AF%94%E8%BE%83%E5%A5%BD%E7%9A%84-gif-%E8%A7%A3%E6%9E%90%E5%BA%93.html

[3]

WPF播放GIF控件完整代码 – CSDN博客: https://blog.csdn.net/Libby1984/article/details/52535085


原文始发于微信公众号(WPF开发者):WPF 播放 gif

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/55226.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!