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         #endregion
233 
234         public void CreateGifAnimation(MemoryStream memoryStream)
235         {
236             Reset();
237 
238             byte[] gifData = memoryStream.GetBuffer();  // Use GetBuffer so that there is no memory copy
239 
240             GifBitmapDecoder decoder = new GifBitmapDecoder(memoryStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
241 
242             numberOfFrames = decoder.Frames.Count;
243 
244             try
245             {
246                 ParseGif(gifData);
247             }
248             catch
249             {
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             else
311             {
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 StretchDirection
116         {
117             get
118             {
119                 return (StretchDirection)this.GetValue(StretchDirectionProperty);
120             }
121             set
122             {
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 ImageFailed
132         {
133             add
134             {
135                 AddHandler(ImageFailedEvent, value);
136             }
137             remove
138             {
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 = (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             try
199             {
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                 else
215                 {
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                     else
228                     {
229                         CreateNonGifAnimationImage();
230                     }
231                 }
232             }
233             else
234             {
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             try
258             {
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                 try
278                 {
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             else
287             {
288                 this.Dispatcher.Invoke(DispatcherPriority.Render, new WebRequestFinishedDelegate(WebRequestFinished), webReadState.memoryStream);
289             }
290         }
291 
292         private void GetGifStreamFromHttp(Uri uri)
293         {
294             try
295             {
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 = 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             try
328             {
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                 else
340                 {
341                     if (uri.GetLeftPart(UriPartial.Authority).Contains("siteoforigin"))
342                     {
343                         streamInfo = Application.GetRemoteStream(uri);
344                     }
345                     else
346                     {
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 };


 

原文地址:https://www.cnblogs.com/gaobing/p/3809587.html