zoukankan      html  css  js  c++  java
  • WPF 显示GIF动画

    简单的通过GifBitmapDecoder解析GIF图片,获取gif帧数和每一帧数据,然后通过时间切换显示,效果如下:

    代码如下:

    namespace GIfImageApplication
    {
        public class GifImageExceptionRoutedEventArgs : RoutedEventArgs
        {
            public Exception ErrorException;
    
            public GifImageExceptionRoutedEventArgs(RoutedEvent routedEvent, object obj)
                : base(routedEvent, obj)
            {
            }
        }
    
        public class WebReadState
        {
            public WebRequest webRequest;
            public MemoryStream memoryStream;
            public Stream readStream;
            public byte[] buffer;
        }
    
    
        public class GifImage : System.Windows.Controls.UserControl
        {
            private GifAnimation gifAnimation = null;
            private Image image = null;
    
            public static readonly DependencyProperty ForceGifAnimProperty = DependencyProperty.Register("ForceGifAnim", typeof(bool), typeof(GifImage), new FrameworkPropertyMetadata(false));
            public bool ForceGifAnim
            {
                get
                {
                    return (bool)this.GetValue(ForceGifAnimProperty);
                }
                set
                {
                    this.SetValue(ForceGifAnimProperty, value);
                }
            }
    
            public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(string), typeof(GifImage), new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnSourceChanged)));
            private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                GifImage obj = (GifImage)d;
                string s = (string)e.NewValue;
                obj.CreateFromSourceString(s);
            }
            public string Source
            {
                get
                {
                    return (string)this.GetValue(SourceProperty);
                }
                set
                {
                    this.SetValue(SourceProperty, value);
                }
            }
    
    
            public static readonly DependencyProperty StretchProperty = DependencyProperty.Register("Stretch", typeof(Stretch), typeof(GifImage), new FrameworkPropertyMetadata(Stretch.Fill, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnStretchChanged)));
            private static void OnStretchChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                GifImage obj = (GifImage)d;
                Stretch s = (Stretch)e.NewValue;
                if (obj.gifAnimation != null)
                {
                    obj.gifAnimation.Stretch = s;
                }
                else if (obj.image != null)
                {
                    obj.image.Stretch = s;
                }
            }
            public Stretch Stretch
            {
                get
                {
                    return (Stretch)this.GetValue(StretchProperty);
                }
                set
                {
                    this.SetValue(StretchProperty, value);
                }
            }
    
            public static readonly DependencyProperty StretchDirectionProperty = DependencyProperty.Register("StretchDirection", typeof(StretchDirection), typeof(GifImage), new FrameworkPropertyMetadata(StretchDirection.Both, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnStretchDirectionChanged)));
            private static void OnStretchDirectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
            {
                GifImage obj = (GifImage)d;
                StretchDirection s = (StretchDirection)e.NewValue;
                if (obj.gifAnimation != null)
                {
                    obj.gifAnimation.StretchDirection = s;
                }
                else if (obj.image != null)
                {
                    obj.image.StretchDirection = s;
                }
            }
            public StretchDirection StretchDirection
            {
                get
                {
                    return (StretchDirection)this.GetValue(StretchDirectionProperty);
                }
                set
                {
                    this.SetValue(StretchDirectionProperty, value);
                }
            }
    
            public delegate void ExceptionRoutedEventHandler(object sender, GifImageExceptionRoutedEventArgs args);
    
            public static readonly RoutedEvent ImageFailedEvent = EventManager.RegisterRoutedEvent("ImageFailed", RoutingStrategy.Bubble, typeof(ExceptionRoutedEventHandler), typeof(GifImage));
    
            public event ExceptionRoutedEventHandler ImageFailed
            {
                add
                {
                    AddHandler(ImageFailedEvent, value);
                }
                remove
                {
                    RemoveHandler(ImageFailedEvent, value);
                }
            }
    
            void image_ImageFailed(object sender, ExceptionRoutedEventArgs e)
            {
                RaiseImageFailedEvent(e.ErrorException);
            }
    
    
            void RaiseImageFailedEvent(Exception exp)
            {
                GifImageExceptionRoutedEventArgs newArgs = new GifImageExceptionRoutedEventArgs(ImageFailedEvent, this);
                newArgs.ErrorException = exp;
                RaiseEvent(newArgs);
            }
    
    
            private void DeletePreviousImage()
            {
                if (image != null)
                {
                    this.RemoveLogicalChild(image);
                    image = null;
                }
                if (gifAnimation != null)
                {
                    this.RemoveLogicalChild(gifAnimation);
                    gifAnimation = null;
                }
            }
    
            private void CreateNonGifAnimationImage()
            {
                image = new Image();
                image.ImageFailed += new EventHandler<ExceptionRoutedEventArgs>(image_ImageFailed);
                ImageSource src = (ImageSource)(new ImageSourceConverter().ConvertFromString(Source));
                image.Source = src;
                image.Stretch = Stretch;
                image.StretchDirection = StretchDirection;
                this.AddChild(image);
            }
    
    
            private void CreateGifAnimation(MemoryStream memoryStream)
            {
                gifAnimation = new GifAnimation();
                gifAnimation.CreateGifAnimation(memoryStream);
                gifAnimation.Stretch = Stretch;
                gifAnimation.StretchDirection = StretchDirection;
                this.AddChild(gifAnimation);
            }
    
    
            private void CreateFromSourceString(string source)
            {
                DeletePreviousImage();
                Uri uri;
    
                try
                {
                    uri = new Uri(source, UriKind.RelativeOrAbsolute);
                }
                catch (Exception exp)
                {
                    RaiseImageFailedEvent(exp);
                    return;
                }
    
                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
                        {
                            CreateNonGifAnimationImage();
                        }
                    }
                }
                else
                {
                    CreateNonGifAnimationImage();
                }
            }
    
            private delegate void WebRequestFinishedDelegate(MemoryStream memoryStream);
    
            private void WebRequestFinished(MemoryStream memoryStream)
            {
                CreateGifAnimation(memoryStream);
            }
    
            private delegate void WebRequestErrorDelegate(Exception exp);
    
            private void WebRequestError(Exception exp)
            {
                RaiseImageFailedEvent(exp);
            }
    
            private void WebResponseCallback(IAsyncResult asyncResult)
            {
                WebReadState webReadState = (WebReadState)asyncResult.AsyncState;
                WebResponse webResponse;
                try
                {
                    webResponse = webReadState.webRequest.EndGetResponse(asyncResult);
                    webReadState.readStream = webResponse.GetResponseStream();
                    webReadState.buffer = new byte[100000];
                    webReadState.readStream.BeginRead(webReadState.buffer, 0, webReadState.buffer.Length, new AsyncCallback(WebReadCallback), webReadState);
                }
                catch (WebException exp)
                {
                    this.Dispatcher.Invoke(DispatcherPriority.Render, new WebRequestErrorDelegate(WebRequestError), exp);
                }
            }
    
            private void WebReadCallback(IAsyncResult asyncResult)
            {
                WebReadState webReadState = (WebReadState)asyncResult.AsyncState;
                int count = webReadState.readStream.EndRead(asyncResult);
                if (count > 0)
                {
                    webReadState.memoryStream.Write(webReadState.buffer, 0, count);
                    try
                    {
                        webReadState.readStream.BeginRead(webReadState.buffer, 0, webReadState.buffer.Length, new AsyncCallback(WebReadCallback), webReadState);
                    }
                    catch (WebException exp)
                    {
                        this.Dispatcher.Invoke(DispatcherPriority.Render, new WebRequestErrorDelegate(WebRequestError), exp);
                    }
                }
                else
                {
                    this.Dispatcher.Invoke(DispatcherPriority.Render, new WebRequestFinishedDelegate(WebRequestFinished), webReadState.memoryStream);
                }
            }
    
            private void GetGifStreamFromHttp(Uri uri)
            {
                try
                {
                    WebReadState webReadState = new WebReadState();
                    webReadState.memoryStream = new MemoryStream();
                    webReadState.webRequest = WebRequest.Create(uri);
                    webReadState.webRequest.Timeout = 10000;
    
                    webReadState.webRequest.BeginGetResponse(new AsyncCallback(WebResponseCallback), webReadState);
                }
                catch (SecurityException)
                {
                    CreateNonGifAnimationImage();
                }
            }
    
    
            private void ReadGifStreamSynch(Stream s)
            {
                byte[] gifData;
                MemoryStream memoryStream;
                using (s)
                {
                    memoryStream = new MemoryStream((int)s.Length);
                    BinaryReader br = new BinaryReader(s);
                    gifData = br.ReadBytes((int)s.Length);
                    memoryStream.Write(gifData, 0, (int)s.Length);
                    memoryStream.Flush();
                }
                CreateGifAnimation(memoryStream);
            }
    
            private void GetGifStreamFromPack(Uri uri)
            {
                try
                {
                    StreamResourceInfo streamInfo;
    
                    if (!uri.IsAbsoluteUri)
                    {
                        streamInfo = Application.GetContentStream(uri);
                        if (streamInfo == null)
                        {
                            streamInfo = Application.GetResourceStream(uri);
                        }
                    }
                    else
                    {
                        if (uri.GetLeftPart(UriPartial.Authority).Contains("siteoforigin"))
                        {
                            streamInfo = Application.GetRemoteStream(uri);
                        }
                        else
                        {
                            streamInfo = Application.GetContentStream(uri);
                            if (streamInfo == null)
                            {
                                streamInfo = Application.GetResourceStream(uri);
                            }
                        }
                    }
                    if (streamInfo == null)
                    {
                        throw new FileNotFoundException("Resource not found.", uri.ToString());
                    }
                    ReadGifStreamSynch(streamInfo.Stream);
                }
                catch (Exception exp)
                {
                    RaiseImageFailedEvent(exp);
                }
            }
        }
    
        class GifAnimation : Viewbox
        {
    
            private class HedmGifFrame : Image
            {
    
                public int delayTime;
    
                public int disposalMethod;
    
                public int left;
    
                public int top;
    
                public int width;
    
                public int height;
            }
    
            private Canvas canvas = null;
    
            private List<HedmGifFrame> frameList = null;
    
            private int frameCounter = 0;
            private int numberOfFrames = 0;
    
            private int numberOfLoops = -1;
            private int currentLoop = 0;
    
            private int logicalWidth = 0;
            private int logicalHeight = 0;
    
            private DispatcherTimer frameTimer = null;
    
            private HedmGifFrame currentParseGifFrame;
    
            public GifAnimation()
            {
                canvas = new Canvas();
                this.Child = canvas;
            }
    
            private void Reset()
            {
                if (frameList != null)
                {
                    frameList.Clear();
                }
                frameList = null;
                frameCounter = 0;
                numberOfFrames = 0;
                numberOfLoops = -1;
                currentLoop = 0;
                logicalWidth = 0;
                logicalHeight = 0;
                if (frameTimer != null)
                {
                    frameTimer.Stop();
                    frameTimer = null;
                }
            }
    
            #region PARSE
            private void ParseGif(byte[] gifData)
            {
                frameList = new List<HedmGifFrame>();
                currentParseGifFrame = new HedmGifFrame();
                ParseGifDataStream(gifData, 0);
            }
    
    
            private int ParseBlock(byte[] gifData, int offset)
            {
                switch (gifData[offset])
                {
                    case 0x21:
                        if (gifData[offset + 1] == 0xF9)
                        {
                            return ParseGraphicControlExtension(gifData, offset);
                        }
                        else
                        {
                            return ParseExtensionBlock(gifData, offset);
                        }
                    case 0x2C:
                        offset = ParseGraphicBlock(gifData, offset);
                        frameList.Add(currentParseGifFrame);
                        currentParseGifFrame = new HedmGifFrame();
                        return offset;
                    case 0x3B:
                        return -1;
                    default:
                        throw new Exception("GIF format incorrect: missing graphic block or special-purpose block. ");
                }
            }
    
            private int ParseGraphicControlExtension(byte[] gifData, int offset)
            {
                int returnOffset = offset;
                int length = gifData[offset + 2];
                returnOffset = offset + length + 2 + 1;
    
                byte packedField = gifData[offset + 3];
                currentParseGifFrame.disposalMethod = (packedField & 0x1C) >> 2;
    
                int delay = BitConverter.ToUInt16(gifData, offset + 4);
                currentParseGifFrame.delayTime = delay;
                while (gifData[returnOffset] != 0x00)
                {
                    returnOffset = returnOffset + gifData[returnOffset] + 1;
                }
    
                returnOffset++;
    
                return returnOffset;
            }
    
            private int ParseLogicalScreen(byte[] gifData, int offset)
            {
                logicalWidth = BitConverter.ToUInt16(gifData, offset);
                logicalHeight = BitConverter.ToUInt16(gifData, offset + 2);
    
                byte packedField = gifData[offset + 4];
                bool hasGlobalColorTable = (int)(packedField & 0x80) > 0 ? true : false;
    
                int currentIndex = offset + 7;
                if (hasGlobalColorTable)
                {
                    int colorTableLength = packedField & 0x07;
                    colorTableLength = (int)Math.Pow(2, colorTableLength + 1) * 3;
                    currentIndex = currentIndex + colorTableLength;
                }
                return currentIndex;
            }
    
            private int ParseGraphicBlock(byte[] gifData, int offset)
            {
                currentParseGifFrame.left = BitConverter.ToUInt16(gifData, offset + 1);
                currentParseGifFrame.top = BitConverter.ToUInt16(gifData, offset + 3);
                currentParseGifFrame.width = BitConverter.ToUInt16(gifData, offset + 5);
                currentParseGifFrame.height = BitConverter.ToUInt16(gifData, offset + 7);
                if (currentParseGifFrame.width > logicalWidth)
                {
                    logicalWidth = currentParseGifFrame.width;
                }
                if (currentParseGifFrame.height > logicalHeight)
                {
                    logicalHeight = currentParseGifFrame.height;
                }
                byte packedField = gifData[offset + 9];
                bool hasLocalColorTable = (int)(packedField & 0x80) > 0 ? true : false;
    
                int currentIndex = offset + 9;
                if (hasLocalColorTable)
                {
                    int colorTableLength = packedField & 0x07;
                    colorTableLength = (int)Math.Pow(2, colorTableLength + 1) * 3;
                    currentIndex = currentIndex + colorTableLength;
                }
                currentIndex++;
    
                currentIndex++;
    
                while (gifData[currentIndex] != 0x00)
                {
                    int length = gifData[currentIndex];
                    currentIndex = currentIndex + gifData[currentIndex];
                    currentIndex++;
                }
                currentIndex = currentIndex + 1;
                return currentIndex;
            }
    
            private int ParseExtensionBlock(byte[] gifData, int offset)
            {
                int returnOffset = offset;
                int length = gifData[offset + 2];
                returnOffset = offset + length + 2 + 1;
                if (gifData[offset + 1] == 0xFF && length > 10)
                {
                    string netscape = System.Text.ASCIIEncoding.ASCII.GetString(gifData, offset + 3, 8);
                    if (netscape == "NETSCAPE")
                    {
                        numberOfLoops = BitConverter.ToUInt16(gifData, offset + 16);
                        if (numberOfLoops > 0)
                        {
                            numberOfLoops++;
                        }
                    }
                }
                while (gifData[returnOffset] != 0x00)
                {
                    returnOffset = returnOffset + gifData[returnOffset] + 1;
                }
    
                returnOffset++;
    
                return returnOffset;
            }
    
            private int ParseHeader(byte[] gifData, int offset)
            {
                string str = System.Text.ASCIIEncoding.ASCII.GetString(gifData, offset, 3);
                if (str != "GIF")
                {
                    throw new Exception("Not a proper GIF file: missing GIF header");
                }
                return 6;
            }
    
            private void ParseGifDataStream(byte[] gifData, int offset)
            {
                offset = ParseHeader(gifData, offset);
                offset = ParseLogicalScreen(gifData, offset);
                while (offset != -1)
                {
                    offset = ParseBlock(gifData, offset);
                }
            }
    
            #endregion
    
            public void CreateGifAnimation(MemoryStream memoryStream)
            {
                try
                {
                    Reset();
    
                    byte[] gifData = memoryStream.GetBuffer();  // Use GetBuffer so that there is no memory copy
    
                    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();
                    }
                }
                finally
                {
                }
            }
    
            public void NextFrame()
            {
                NextFrame(null, null);
            }
    
            public void NextFrame(object sender, EventArgs e)
            {
                frameTimer.Stop();
                if (numberOfFrames == 0) return;
                if (frameList[frameCounter].disposalMethod == 2)
                {
                    frameList[frameCounter].Visibility = Visibility.Hidden;
                }
                if (frameList[frameCounter].disposalMethod >= 3)
                {
                    frameList[frameCounter].Visibility = Visibility.Hidden;
                }
                frameCounter++;
    
                if (frameCounter < numberOfFrames)
                {
                    frameList[frameCounter].Visibility = Visibility.Visible;
                    frameTimer.Interval = new TimeSpan(0, 0, 0, 0, frameList[frameCounter].delayTime * 10);
                    frameTimer.Start();
                }
                else
                {
                    if (numberOfLoops != 0)
                    {
                        currentLoop++;
                    }
                    if (currentLoop < numberOfLoops || numberOfLoops == 0)
                    {
                        for (int f = 0; f < frameList.Count; f++)
                        {
                            frameList[f].Visibility = Visibility.Hidden;
                        }
                        frameCounter = 0;
                        frameList[frameCounter].Visibility = Visibility.Visible;
                        frameTimer.Interval = new TimeSpan(0, 0, 0, 0, frameList[frameCounter].delayTime * 10);
                        frameTimer.Start();
                    }
                }
            }
        }
    }
    

    使用:

     <Gif:GifImage Source="loading.gif" ></Gif:GifImage>
    

     

  • 相关阅读:
    php测试数据库
    mysql查
    mysql增删改
    mysql数据类型
    Docker 探索安装WordPress+Mysql8.0
    Docker For MYSQL 8.0 特别注意修复数据库新的验证方式
    Docker EE/Docker CE简介与版本规划
    Hyper和Vmware冲突,Device/Credential Guard 不兼容
    利用阿里云加速Docker For Windows
    使用Aliyun Docker 容器镜像/注册表服务
  • 原文地址:https://www.cnblogs.com/xiamojinnian/p/5007880.html
Copyright © 2011-2022 走看看