【WPF】Image控制元件顯示Gif圖片
阿新 • • 發佈:2022-05-12
class GifImage : Image { private bool _isInitialized; private GifBitmapDecoder _gifDecoder; private Int32Animation _animation; public int FrameIndex { get { return (int)GetValue(FrameIndexProperty); } set { SetValue(FrameIndexProperty, value); } }private void Initialize() { _gifDecoder = new GifBitmapDecoder(new Uri((this.GifSource.StartsWith("pack://") ? "" : "pack://application:,,,") + this.GifSource), BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default); var frameinfo = _gifDecoder.Metadata.GetFrameInfo();var delay = frameinfo.Delay; _animation = new Int32Animation(0, _gifDecoder.Frames.Count - 1, new Duration(new TimeSpan(0, 0, 0, delay.Seconds * _gifDecoder.Frames.Count + (delay.Milliseconds * _gifDecoder.Frames.Count) / 1000, (delay.Milliseconds * _gifDecoder.Frames.Count) % 1000))); _animation.RepeatBehavior= RepeatBehavior.Forever; this.Source = _gifDecoder.Frames[0]; _isInitialized = true; } static GifImage() { VisibilityProperty.OverrideMetadata(typeof(GifImage), new FrameworkPropertyMetadata(VisibilityPropertyChanged)); } private static void VisibilityPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { if ((Visibility)e.NewValue == Visibility.Visible) { ((GifImage)sender).StartAnimation(); } else { ((GifImage)sender).StopAnimation(); } } public static readonly DependencyProperty FrameIndexProperty = DependencyProperty.Register("FrameIndex", typeof(int), typeof(GifImage), new UIPropertyMetadata(0, new PropertyChangedCallback(ChangingFrameIndex))); static void ChangingFrameIndex(DependencyObject obj, DependencyPropertyChangedEventArgs ev) { var gifImage = obj as GifImage; gifImage.Source = gifImage._gifDecoder.Frames[(int)ev.NewValue]; } /// <summary> /// Defines whether the animation starts on it's own /// </summary> public bool AutoStart { get { return (bool)GetValue(AutoStartProperty); } set { SetValue(AutoStartProperty, value); } } public static readonly DependencyProperty AutoStartProperty = DependencyProperty.Register("AutoStart", typeof(bool), typeof(GifImage), new UIPropertyMetadata(false, AutoStartPropertyChanged)); private static void AutoStartPropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { if ((bool)e.NewValue) (sender as GifImage).StartAnimation(); } public string GifSource { get { return (string)GetValue(GifSourceProperty); } set { SetValue(GifSourceProperty, value); } } public static readonly DependencyProperty GifSourceProperty = DependencyProperty.Register("GifSource", typeof(string), typeof(GifImage), new UIPropertyMetadata(string.Empty, GifSourcePropertyChanged)); private static void GifSourcePropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e) { (sender as GifImage).Initialize(); } /// <summary> /// Starts the animation /// </summary> public void StartAnimation() { if (!_isInitialized) this.Initialize(); BeginAnimation(FrameIndexProperty, _animation); } /// <summary> /// Stops the animation /// </summary> public void StopAnimation() { BeginAnimation(FrameIndexProperty, null); } }
enum FrameDisposalMethod { Replace = 0, Combine = 1, RestoreBackground = 2, RestorePrevious = 3 }
class FrameInfo { /// <summary> /// 兩個圖片的時間 /// </summary> public TimeSpan Delay { get; set; } /// <summary> /// 圖片是如何顯示 /// </summary> 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); } } }
static class BitmapMetadataMethod { public static FrameInfo GetFrameInfo(this BitmapMetadata metadata) { var frameInfo = new FrameInfo { Delay = TimeSpan.FromMilliseconds(100), DisposalMethod = FrameDisposalMethod.Replace, Width = 0, Height = 0, Left = 0, Top = 0 }; try { 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; } public 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; } }
前端使用:
<local:GifImage x:Name="gifImage" Width="400" Height="300" Stretch="UniformToFill" GifSource="pack://application:,,,/FamilyParamReader;Component/Image/loading.gif" AutoStart="True" />
不知道是不是我圖片問題,迴圈播放的時候,起始的位置總會有閃一下。不知道怎麼解決。
參考文章:
https://blog.csdn.net/weixin_30628077/article/details/97698859
https://thomaslevesque.com/2011/03/27/wpf-display-an-animated-gif-image/
https://stackoverflow.com/questions/210922/how-do-i-get-an-animated-gif-to-work-in-wpf