首页 > 代码库 > WPF 显示gif

WPF 显示gif

  1 using System;  2 using System.IO;  3 using System.Collections.Generic;  4 using System.Windows;  5 using System.Windows.Controls;  6 using System.Windows.Media.Imaging;  7 using System.Windows.Threading;  8   9 namespace GifImageLib 10 { 11      12     class GifAnimation : Viewbox 13     { 14         15         private class GifFrame : Image 16         { 17              18             public int delayTime; 19  20             public int disposalMethod; 21             22             public int left; 23              24             public int top; 25              26             public int width; 27              28             public int height; 29         } 30  31         private Canvas canvas = null; 32  33         private List<GifFrame> frameList = null; 34  35         private int frameCounter = 0; 36         private int numberOfFrames = 0; 37  38         private int numberOfLoops = -1; 39         private int currentLoop = 0; 40  41         private int logicalWidth = 0; 42         private int logicalHeight = 0; 43  44         private DispatcherTimer frameTimer = null; 45  46         private GifFrame currentParseGifFrame; 47  48         public GifAnimation() 49         { 50             canvas = new Canvas(); 51             this.Child = canvas; 52         } 53  54         private void Reset() 55         { 56             if (frameList != null) 57             { 58                 frameList.Clear(); 59             } 60             frameList = null; 61             frameCounter = 0; 62             numberOfFrames = 0; 63             numberOfLoops = -1; 64             currentLoop = 0; 65             logicalWidth = 0; 66             logicalHeight = 0; 67             if (frameTimer != null) 68             { 69                 frameTimer.Stop(); 70                 frameTimer = null; 71             } 72         } 73  74         #region PARSE 75         private void ParseGif(byte[] gifData) 76         { 77             frameList = new List<GifFrame>(); 78             currentParseGifFrame = new GifFrame(); 79             ParseGifDataStream(gifData, 0); 80         } 81  82         83         private int ParseBlock(byte[] gifData, int offset) 84         { 85             switch (gifData[offset]) 86             { 87                 case 0x21: 88                     if (gifData[offset + 1] == 0xF9) 89                     { 90                         return ParseGraphicControlExtension(gifData, offset); 91                     } 92                     else 93                     { 94                         return ParseExtensionBlock(gifData, offset); 95                     } 96                 case 0x2C: 97                     offset = ParseGraphicBlock(gifData, offset); 98                     frameList.Add(currentParseGifFrame); 99                     currentParseGifFrame = new GifFrame();100                     return offset;101                 case 0x3B:102                     return -1;103                 default:104                     throw new Exception("GIF format incorrect: missing graphic block or special-purpose block. ");105             }106         }107 108         private int ParseGraphicControlExtension(byte[] gifData, int offset)109         {110             int returnOffset = offset;111             int length = gifData[offset + 2];112             returnOffset = offset + length + 2 + 1;113 114             byte packedField = gifData[offset + 3];115             currentParseGifFrame.disposalMethod = (packedField & 0x1C) >> 2;116 117             int delay = BitConverter.ToUInt16(gifData, offset + 4);118             currentParseGifFrame.delayTime = delay;119             while (gifData[returnOffset] != 0x00)120             {121                 returnOffset = returnOffset + gifData[returnOffset] + 1;122             }123 124             returnOffset++;125 126             return returnOffset;127         }128 129         private int ParseLogicalScreen(byte[] gifData, int offset)130         {131             logicalWidth = BitConverter.ToUInt16(gifData, offset);132             logicalHeight = BitConverter.ToUInt16(gifData, offset + 2);133 134             byte packedField = gifData[offset + 4];135             bool hasGlobalColorTable = (int)(packedField & 0x80) > 0 ? true : false;136 137             int currentIndex = offset + 7;138             if (hasGlobalColorTable)139             {140                 int colorTableLength = packedField & 0x07;141                 colorTableLength = (int)Math.Pow(2, colorTableLength + 1) * 3;142                 currentIndex = currentIndex + colorTableLength;143             }144             return currentIndex;145         }146 147         private int ParseGraphicBlock(byte[] gifData, int offset)148         {149             currentParseGifFrame.left = BitConverter.ToUInt16(gifData, offset + 1);150             currentParseGifFrame.top = BitConverter.ToUInt16(gifData, offset + 3);151             currentParseGifFrame.width = BitConverter.ToUInt16(gifData, offset + 5);152             currentParseGifFrame.height = BitConverter.ToUInt16(gifData, offset + 7);153             if (currentParseGifFrame.width > logicalWidth)154             {155                 logicalWidth = currentParseGifFrame.width;156             }157             if (currentParseGifFrame.height > logicalHeight)158             {159                 logicalHeight = currentParseGifFrame.height;160             }161             byte packedField = gifData[offset + 9];162             bool hasLocalColorTable = (int)(packedField & 0x80) > 0 ? true : false;163 164             int currentIndex = offset + 9;165             if (hasLocalColorTable)166             {167                 int colorTableLength = packedField & 0x07;168                 colorTableLength = (int)Math.Pow(2, colorTableLength + 1) * 3;169                 currentIndex = currentIndex + colorTableLength;170             }171             currentIndex++; 172 173             currentIndex++; 174 175             while (gifData[currentIndex] != 0x00)176             {177                 int length = gifData[currentIndex];178                 currentIndex = currentIndex + gifData[currentIndex];179                 currentIndex++; 180             }181             currentIndex = currentIndex + 1;182             return currentIndex;183         }184 185         private int ParseExtensionBlock(byte[] gifData, int offset)186         {187             int returnOffset = offset;188             int length = gifData[offset + 2];189             returnOffset = offset + length + 2 + 1;190             if (gifData[offset + 1] == 0xFF && length > 10)191             {192                 string netscape = System.Text.ASCIIEncoding.ASCII.GetString(gifData, offset + 3, 8);193                 if (netscape == "NETSCAPE")194                 {195                     numberOfLoops = BitConverter.ToUInt16(gifData, offset + 16);196                     if (numberOfLoops > 0)197                     {198                         numberOfLoops++;199                     }200                 }201             }202             while (gifData[returnOffset] != 0x00)203             {204                 returnOffset = returnOffset + gifData[returnOffset] + 1;205             }206 207             returnOffset++;208 209             return returnOffset;210         }211 212         private int ParseHeader(byte[] gifData, int offset)213         {214             string str = System.Text.ASCIIEncoding.ASCII.GetString(gifData, offset, 3);215             if (str != "GIF")216             {217                 throw new Exception("Not a proper GIF file: missing GIF header");218             }219             return 6;220         }221 222         private void ParseGifDataStream(byte[] gifData, int offset)223         {224             offset = ParseHeader(gifData, offset);225             offset = ParseLogicalScreen(gifData, offset);226             while (offset != -1)227             {228                 offset = ParseBlock(gifData, offset);229             }230         }231 232         #endregion233 234         public void CreateGifAnimation(MemoryStream memoryStream)235         {236             Reset();237 238             byte[] gifData = http://www.mamicode.com/memoryStream.GetBuffer();  // Use GetBuffer so that there is no memory copy239 240             GifBitmapDecoder decoder = new GifBitmapDecoder(memoryStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);241 242             numberOfFrames = decoder.Frames.Count;243 244             try245             {246                 ParseGif(gifData);247             }248             catch249             {250                 throw new FileFormatException("Unable to parse Gif file format.");251             }252 253             for (int i = 0; i < decoder.Frames.Count; i++)254             {255                 frameList[i].Source = decoder.Frames[i];256                 frameList[i].Visibility = Visibility.Hidden;257                 canvas.Children.Add(frameList[i]);258                 Canvas.SetLeft(frameList[i], frameList[i].left);259                 Canvas.SetTop(frameList[i], frameList[i].top);260                 Canvas.SetZIndex(frameList[i], i);261             }262             canvas.Height = logicalHeight;263             canvas.Width = logicalWidth;264 265             frameList[0].Visibility = Visibility.Visible;266 267             for (int i = 0; i < frameList.Count; i++)268             {269                 Console.WriteLine(frameList[i].disposalMethod.ToString() + " " + frameList[i].width.ToString() + " " + frameList[i].delayTime.ToString());270             }271 272             if (frameList.Count > 1)273             {274                 if (numberOfLoops == -1)275                 {276                     numberOfLoops = 1;277                 }278                 frameTimer = new System.Windows.Threading.DispatcherTimer();279                 frameTimer.Tick += NextFrame;280                 frameTimer.Interval = new TimeSpan(0, 0, 0, 0, frameList[0].delayTime * 10);281                 frameTimer.Start();282             }283         }284 285         public void NextFrame()286         {287             NextFrame(null, null);288         }289 290         public void NextFrame(object sender, EventArgs e)291         {292             frameTimer.Stop();293             if (numberOfFrames == 0) return;294             if (frameList[frameCounter].disposalMethod == 2)295             {296                 frameList[frameCounter].Visibility = Visibility.Hidden;297             }298             if (frameList[frameCounter].disposalMethod >= 3)299             {300                 frameList[frameCounter].Visibility = Visibility.Hidden;301             }302             frameCounter++;303 304             if (frameCounter < numberOfFrames)305             {306                 frameList[frameCounter].Visibility = Visibility.Visible;307                 frameTimer.Interval = new TimeSpan(0, 0, 0, 0, frameList[frameCounter].delayTime * 10);308                 frameTimer.Start();309             }310             else311             {312                 if (numberOfLoops != 0)313                 {314                     currentLoop++;315                 }316                 if (currentLoop < numberOfLoops || numberOfLoops == 0)317                 {318                     for (int f = 0; f < frameList.Count; f++)319                     {320                         frameList[f].Visibility = Visibility.Hidden;321                     }322                     frameCounter = 0;323                     frameList[frameCounter].Visibility = Visibility.Visible;324                     frameTimer.Interval = new TimeSpan(0, 0, 0, 0, frameList[frameCounter].delayTime * 10);325                     frameTimer.Start();326                 }327             }328         }329     }330 }
GifAnimation

 

  1 using System.Net;  2 using System.IO;  3 using System.Security;  4 using System.Windows;  5 using System.Windows.Controls;  6 using System.Windows.Media;  7 using System.Windows.Media.Imaging;  8 using System.Windows.Threading;  9 using System.Windows.Resources; 10 using System; 11  12 namespace GifImageLib 13 { 14     public class GifImageExceptionRoutedEventArgs : RoutedEventArgs 15     { 16         public Exception ErrorException; 17  18         public GifImageExceptionRoutedEventArgs(RoutedEvent routedEvent, object obj) 19             : base(routedEvent, obj) 20         { 21         } 22     } 23  24     class WebReadState 25     { 26         public WebRequest webRequest; 27         public MemoryStream memoryStream; 28         public Stream readStream; 29         public byte[] buffer; 30     } 31  32  33     public class GifImage : System.Windows.Controls.UserControl 34     { 35         private GifAnimation gifAnimation = null; 36         private Image image = null; 37  38         public GifImage() 39         { 40         } 41  42         public static readonly DependencyProperty ForceGifAnimProperty = DependencyProperty.Register("ForceGifAnim", typeof(bool), typeof(GifImage), new FrameworkPropertyMetadata(false)); 43         public bool ForceGifAnim 44         { 45             get 46             { 47                 return (bool)this.GetValue(ForceGifAnimProperty); 48             } 49             set 50             { 51                 this.SetValue(ForceGifAnimProperty, value); 52             } 53         } 54  55         public static readonly DependencyProperty SourceProperty = DependencyProperty.Register("Source", typeof(string), typeof(GifImage), new FrameworkPropertyMetadata("", FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender, new PropertyChangedCallback(OnSourceChanged))); 56         private static void OnSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 57         { 58             GifImage obj = (GifImage)d; 59             string s = (string)e.NewValue; 60             obj.CreateFromSourceString(s); 61         } 62         public string Source 63         { 64             get 65             { 66                 return (string)this.GetValue(SourceProperty); 67             } 68             set 69             { 70                 this.SetValue(SourceProperty, value); 71             } 72         } 73  74  75         public static readonly DependencyProperty StretchProperty = DependencyProperty.Register("Stretch", typeof(Stretch), typeof(GifImage), new FrameworkPropertyMetadata(Stretch.Fill, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnStretchChanged))); 76         private static void OnStretchChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 77         { 78             GifImage obj = (GifImage)d; 79             Stretch s = (Stretch)e.NewValue; 80             if (obj.gifAnimation != null) 81             { 82                 obj.gifAnimation.Stretch = s; 83             } 84             else if (obj.image != null) 85             { 86                 obj.image.Stretch = s; 87             } 88         } 89         public Stretch Stretch 90         { 91             get 92             { 93                 return (Stretch)this.GetValue(StretchProperty); 94             } 95             set 96             { 97                 this.SetValue(StretchProperty, value); 98             } 99         }100 101         public static readonly DependencyProperty StretchDirectionProperty = DependencyProperty.Register("StretchDirection", typeof(StretchDirection), typeof(GifImage), new FrameworkPropertyMetadata(StretchDirection.Both, FrameworkPropertyMetadataOptions.AffectsMeasure, new PropertyChangedCallback(OnStretchDirectionChanged)));102         private static void OnStretchDirectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)103         {104             GifImage obj = (GifImage)d;105             StretchDirection s = (StretchDirection)e.NewValue;106             if (obj.gifAnimation != null)107             {108                 obj.gifAnimation.StretchDirection = s;109             }110             else if (obj.image != null)111             {112                 obj.image.StretchDirection = s;113             }114         }115         public StretchDirection StretchDirection116         {117             get118             {119                 return (StretchDirection)this.GetValue(StretchDirectionProperty);120             }121             set122             {123                 this.SetValue(StretchDirectionProperty, value);124             }125         }126 127         public delegate void ExceptionRoutedEventHandler(object sender, GifImageExceptionRoutedEventArgs args);128 129         public static readonly RoutedEvent ImageFailedEvent = EventManager.RegisterRoutedEvent("ImageFailed", RoutingStrategy.Bubble, typeof(ExceptionRoutedEventHandler), typeof(GifImage));130 131         public event ExceptionRoutedEventHandler ImageFailed132         {133             add134             {135                 AddHandler(ImageFailedEvent, value);136             }137             remove138             {139                 RemoveHandler(ImageFailedEvent, value);140             }141         }142 143         void image_ImageFailed(object sender, ExceptionRoutedEventArgs e)144         {145             RaiseImageFailedEvent(e.ErrorException);146         }147 148 149         void RaiseImageFailedEvent(Exception exp)150         {151             GifImageExceptionRoutedEventArgs newArgs = new GifImageExceptionRoutedEventArgs(ImageFailedEvent, this);152             newArgs.ErrorException = exp;153             RaiseEvent(newArgs);154         }155 156 157         private void DeletePreviousImage()158         {159             if (image != null)160             {161                 this.RemoveLogicalChild(image);162                 image = null;163             }164             if (gifAnimation != null)165             {166                 this.RemoveLogicalChild(gifAnimation);167                 gifAnimation = null;168             }169         }170 171         private void CreateNonGifAnimationImage()172         {173             image = new Image();174             image.ImageFailed += new EventHandler<ExceptionRoutedEventArgs>(image_ImageFailed);175             ImageSource src = http://www.mamicode.com/(ImageSource)(new ImageSourceConverter().ConvertFromString(Source));176             image.Source = src;177             image.Stretch = Stretch;178             image.StretchDirection = StretchDirection;179             this.AddChild(image);180         }181 182 183         private void CreateGifAnimation(MemoryStream memoryStream)184         {185             gifAnimation = new GifAnimation();186             gifAnimation.CreateGifAnimation(memoryStream);187             gifAnimation.Stretch = Stretch;188             gifAnimation.StretchDirection = StretchDirection;189             this.AddChild(gifAnimation);190         }191 192 193         private void CreateFromSourceString(string source)194         {195             DeletePreviousImage();196             Uri uri;197 198             try199             {200                 uri = new Uri(source, UriKind.RelativeOrAbsolute);201             }202             catch (Exception exp)203             {204                 RaiseImageFailedEvent(exp);205                 return;206             }207 208             if (source.Trim().ToUpper().EndsWith(".GIF") || ForceGifAnim)209             {210                 if (!uri.IsAbsoluteUri)211                 {212                     GetGifStreamFromPack(uri);213                 }214                 else215                 {216 217                     string leftPart = uri.GetLeftPart(UriPartial.Scheme);218 219                     if (leftPart == "http://" || leftPart == "ftp://" || leftPart == "file://")220                     {221                         GetGifStreamFromHttp(uri);222                     }223                     else if (leftPart == "pack://")224                     {225                         GetGifStreamFromPack(uri);226                     }227                     else228                     {229                         CreateNonGifAnimationImage();230                     }231                 }232             }233             else234             {235                 CreateNonGifAnimationImage();236             }237         }238 239         private delegate void WebRequestFinishedDelegate(MemoryStream memoryStream);240 241         private void WebRequestFinished(MemoryStream memoryStream)242         {243             CreateGifAnimation(memoryStream);244         }245 246         private delegate void WebRequestErrorDelegate(Exception exp);247 248         private void WebRequestError(Exception exp)249         {250             RaiseImageFailedEvent(exp);251         }252 253         private void WebResponseCallback(IAsyncResult asyncResult)254         {255             WebReadState webReadState = (WebReadState)asyncResult.AsyncState;256             WebResponse webResponse;257             try258             {259                 webResponse = webReadState.webRequest.EndGetResponse(asyncResult);260                 webReadState.readStream = webResponse.GetResponseStream();261                 webReadState.buffer = new byte[100000];262                 webReadState.readStream.BeginRead(webReadState.buffer, 0, webReadState.buffer.Length, new AsyncCallback(WebReadCallback), webReadState);263             }264             catch (WebException exp)265             {266                 this.Dispatcher.Invoke(DispatcherPriority.Render, new WebRequestErrorDelegate(WebRequestError), exp);267             }268         }269 270         private void WebReadCallback(IAsyncResult asyncResult)271         {272             WebReadState webReadState = (WebReadState)asyncResult.AsyncState;273             int count = webReadState.readStream.EndRead(asyncResult);274             if (count > 0)275             {276                 webReadState.memoryStream.Write(webReadState.buffer, 0, count);277                 try278                 {279                     webReadState.readStream.BeginRead(webReadState.buffer, 0, webReadState.buffer.Length, new AsyncCallback(WebReadCallback), webReadState);280                 }281                 catch (WebException exp)282                 {283                     this.Dispatcher.Invoke(DispatcherPriority.Render, new WebRequestErrorDelegate(WebRequestError), exp);284                 }285             }286             else287             {288                 this.Dispatcher.Invoke(DispatcherPriority.Render, new WebRequestFinishedDelegate(WebRequestFinished), webReadState.memoryStream);289             }290         }291 292         private void GetGifStreamFromHttp(Uri uri)293         {294             try295             {296                 WebReadState webReadState = new WebReadState();297                 webReadState.memoryStream = new MemoryStream();298                 webReadState.webRequest = WebRequest.Create(uri);299                 webReadState.webRequest.Timeout = 10000;300 301                 webReadState.webRequest.BeginGetResponse(new AsyncCallback(WebResponseCallback), webReadState);302             }303             catch (SecurityException)304             {305                 CreateNonGifAnimationImage();306             }307         }308 309 310         private void ReadGifStreamSynch(Stream s)311         {312             byte[] gifData;313             MemoryStream memoryStream;314             using (s)315             {316                 memoryStream = new MemoryStream((int)s.Length);317                 BinaryReader br = new BinaryReader(s);318                 gifData = http://www.mamicode.com/br.ReadBytes((int)s.Length);319                 memoryStream.Write(gifData, 0, (int)s.Length);320                 memoryStream.Flush();321             }322             CreateGifAnimation(memoryStream);323         }324 325         private void GetGifStreamFromPack(Uri uri)326         {327             try328             {329                 StreamResourceInfo streamInfo;330 331                 if (!uri.IsAbsoluteUri)332                 {333                     streamInfo = Application.GetContentStream(uri);334                     if (streamInfo == null)335                     {336                         streamInfo = Application.GetResourceStream(uri);337                     }338                 }339                 else340                 {341                     if (uri.GetLeftPart(UriPartial.Authority).Contains("siteoforigin"))342                     {343                         streamInfo = Application.GetRemoteStream(uri);344                     }345                     else346                     {347                         streamInfo = Application.GetContentStream(uri);348                         if (streamInfo == null)349                         {350                             streamInfo = Application.GetResourceStream(uri);351                         }352                     }353                 }354                 if (streamInfo == null)355                 {356                     throw new FileNotFoundException("Resource not found.", uri.ToString());357                 }358                 ReadGifStreamSynch(streamInfo.Stream);359             }360             catch (Exception exp)361             {362                 RaiseImageFailedEvent(exp);363             }364         }365     }366 }
GifImage

 

使用:

var image = new GifImage { Source = "Path", Stretch = Stretch.Fill };