首页 > 代码库 > 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 }
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 }
使用:
var image = new GifImage { Source = "Path", Stretch = Stretch.Fill };
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。