• 2018-2-13-wpf-GifBitmapDecoder-解析-gif-格式


    title author date CreateTime categories
    wpf GifBitmapDecoder 解析 gif 格式
    lindexi
    2018-2-13 17:23:3 +0800
    2018-2-13 17:23:3 +0800
    WPF gif

    在网上有很多图片都是gif,那么如何在 wpf 解析 gif? 本文告诉大家如何使用 GifBitmapDecoder 把gif分开为一张一张,获得他的信息。

    如果需要把一个 gif 分开,使用的代码很简单

                var file = "E:\林德熙\测试文件\2017年9月1日 10.gif";
                var stream = new FileStream(file, FileMode.Open);
                var decoder = new GifBitmapDecoder(stream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
    

    从 decoder 就可以获得每个图片,例如写一个按钮,按一下就切换一个图片。

          private int n = 0;
    
            private void Button_OnClick(object sender, RoutedEventArgs e)
            {
                var t = decoder.Frames[n];
                
                Image.Source = t;
                n++;
                if (n >= decoder.Frames.Count)
                {
                    n = 0;
                }
            }

    按钮点击如上面代码,可以看到 decoder 把 gif 分开很简单,但是如何获得一帧的时间。如果在 wpf 获得 gif 图片间隔,就需要一些特殊方法。

    先创建一个类 用于获得 gif 的信息,需要知道,每个gif的里面的图片都有信息。

            class FrameInfo
            {
                public TimeSpan Delay { get; set; }
                public FrameDisposalMethod DisposalMethod { get; set; }
                public double Width { get; set; }
                public double Height { get; set; }
                public double Left { get; set; }
                public double Top { get; set; }
    
                public Rect Rect
                {
                    get { return new Rect(Left, Top, Width, Height); }
                }
            }

    其中 Delay 就是两个图片播放的时间,FrameDisposalMethod表示两张图片是如何播放,完全替换前一张还是在前一张基础继续显示。

    获得 gif 的信息需要使用 GetQuery ,这个方法不好用,于是使用下面代码把他转类型

            private static T? GetQueryOrNull<T>(this BitmapMetadata metadata, string query)
                where T : struct
            {
                if (metadata.ContainsQuery(query))
                {
                    object value = metadata.GetQuery(query);
                    if (value != null)
                        return (T) value;
                }
                return null;
            }

    可以看到 decoder 的每个图片的 MetadataImageMetadata ,而且wr也没说它里面有哪些数据。

    实际可以使用BitmapMetadata获得每个图片信息,因为Metadata实际是BitmapMetadata,通过/grctlext/Delay可以获得两个图片的时间,/grctlext/Disposal可以获得两个图片是如何显示,/imgdesc/Width 可以获得宽度。于是使用下面函数可以获得图片信息

            public static FrameInfo GetFrameInfo(BitmapFrame frame)
            {
                var frameInfo = new FrameInfo
                {
                    Delay = TimeSpan.FromMilliseconds(100),
                    DisposalMethod = FrameDisposalMethod.Replace,
                    Width = frame.PixelWidth,
                    Height = frame.PixelHeight,
                    Left = 0,
                    Top = 0
                };
    
                BitmapMetadata metadata;
                try
                {
                    metadata = frame.Metadata as BitmapMetadata;
                    if (metadata != null)
                    {
                        const string delayQuery = "/grctlext/Delay";
                        const string disposalQuery = "/grctlext/Disposal";
                        const string widthQuery = "/imgdesc/Width";
                        const string heightQuery = "/imgdesc/Height";
                        const string leftQuery = "/imgdesc/Left";
                        const string topQuery = "/imgdesc/Top";
    
                        var delay = metadata.GetQueryOrNull<ushort>(delayQuery);
                        if (delay.HasValue)
                            frameInfo.Delay = TimeSpan.FromMilliseconds(10 * delay.Value);
    
                        var disposal = metadata.GetQueryOrNull<byte>(disposalQuery);
                        if (disposal.HasValue)
                            frameInfo.DisposalMethod = (FrameDisposalMethod) disposal.Value;
    
                        var width = metadata.GetQueryOrNull<ushort>(widthQuery);
                        if (width.HasValue)
                            frameInfo.Width = width.Value;
    
                        var height = metadata.GetQueryOrNull<ushort>(heightQuery);
                        if (height.HasValue)
                            frameInfo.Height = height.Value;
    
                        var left = metadata.GetQueryOrNull<ushort>(leftQuery);
                        if (left.HasValue)
                            frameInfo.Left = left.Value;
    
                        var top = metadata.GetQueryOrNull<ushort>(topQuery);
                        if (top.HasValue)
                            frameInfo.Top = top.Value;
                    }
                }
                catch (NotSupportedException)
                {
                }
    
                return frameInfo;
            }
    

    这个方法实际上性能不好,如果需要一个可以用的gif解析,请看我的博客WPF 播放 gif

    参见: http://www.thomaslevesque.com/2011/03/27/wpf-display-an-animated-gif-image/

    http://stackoverflow.com/questions/210922/how-do-i-get-an-animated-gif-to-work-in-wpf

  • 相关阅读:
    自由职业者:如何找到你的第一个客户 【转载】
    MPI教程地址
    多线程程序设计.....
    PE格式的深入理解(一)
    用Hook解决在VC++与C++Builder方面界面设计的一些问题
    ANSI,MBCS,Unicode与使用swprintf的陷阱
    关于单片机程序
    C#操作SharePoint列表
    CAML中比较日期时间类型[转]
    使用C#创建webservice及三种调用方式
  • 原文地址:https://www.cnblogs.com/lindexi/p/12086531.html
Copyright © 2020-2023  润新知