简单的通过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>

 

WPF 显示GIF动画的更多相关文章

  1. WPF显示Gif动画

    WPF的Image控件不能很好的支持.gif文件.解决办法有如下2种. 1使用MediaElement <MediaElement Source="file://D:\anim.gif ...

  2. WPF编程学习——动画

    前言 使用动画,是增强用户体验的一种有效的手段.合理的动画,可以让应用程序的界面看起来更加自然.真实.流畅.舒适,更有效地向用户展现信息,用户也更容易接受.同时也增加了软件使用的乐趣,提高用户粘度.( ...

  3. WPF 有趣的动画效果

    WPF 有趣的动画效果         这一次我要呈上一个简单的文章,关于给你的WPF apps加入美丽的光线动画,可是我对动画这东西可能有点入迷了.         实际上.我对动画如此的入迷,以至 ...

  4. WPF中的动画——(三)时间线(TimeLine)

    WPF中的动画——(三)时间线(TimeLine) 时间线(TimeLine)表示时间段. 它提供的属性可以让控制该时间段的长度.开始时间.重复次数.该时间段内时间进度的快慢等等.在WPF中内置了如下 ...

  5. ActionBar compat 如何禁用ActionBar的显示/隐藏动画

    ActionBar compat 如何关闭ActionBar的显示隐藏动画 @Override public boolean onCreateOptionsMenu(Menu menu) { //消除 ...

  6. WinForm上显示gif动画:转

    WinForm上的ProgressBar,老实说,实在是不敢恭维,太死板,太难看了,即使做成实时显示处理进度的,它还是逃离不了“难看”.现 在的web2.0上到处都能看到一个显示正在处理的小圆圈在那转 ...

  7. C# WPF 显示图片和视频显示 EmuguCv、AForge.Net测试(续)

    介绍 本文是接着上文<C# WPF 显示图片和视频显示 EmuguCv.AForge.Net测试>写的,建议先看下上文,因为有些代码还需要了解. 增添 接着上文的代码,我们可以在事件处理方 ...

  8. Android窗口管理服务WindowManagerService显示窗口动画的原理分析

    文章转载至CSDN社区罗升阳的安卓之旅,原文地址:http://blog.csdn.net/luoshengyang/article/details/8611754 在前一文中,我们分析了Activi ...

  9. Android显示GIF动画完整示例(二)

    MainActivity如下: package cc.testgif2; import android.os.Bundle; import android.app.Activity; /** * De ...

随机推荐

  1. mysql - join two derived tables

    select t1.uid from (select uid from table1) t1 inner join (select uid from table2) t2 where t1.uid=t ...

  2. @ViewDebug.ExportedProperty的使用

    原文链接:http://daemon369.github.io/android/2014/06/12/android-viewdebug-exportedproperty/ http://www.eo ...

  3. SeekBar 圆角问题

    用图片做背景色,最后处理成.9.png的.用普通png图片做背景,则两边会有圆角出现,原因是图片不适合SeekBar尺寸,因而被拉伸或压缩,从而产生圆角. <?xml version=" ...

  4. 关于readdir返回值中struct dirent.d_type的取值有关问题(转)

    关于readdir返回值中struct dirent.d_type的取值问题 原网页链接 http://www.gnu.org/software/libc/manual/html_node/Direc ...

  5. 第一章 删掉centos原有的openjdk并安装sun jdk

    一.卸载原有openjdk rpm -qa | grep java 之后,将展示出来的全部卸载掉,我这里是5个 rpm -e --nodeps java-1.7.0-openjdk-1.7.0.111 ...

  6. Java监控工具介绍,VisualVm ,JProfiler,Perfino,Yourkit,Perf4J,JProbe,Java微基准测试

    本文是本人前一段时间做一个简单Java监控工具调研总结,主要包括VisualVm ,JProfiler,Perfino,Yourkit,Perf4J,JProbe,以及对Java微基准测试的简单介绍, ...

  7. SpringMVC对异常进行全局处理,并区分对待ajax和普通请求

    异常信息应统一进行处理. 程序员开发过程中,应尽量少用try..catch.避免因为catch造成的业务歧义.而在web开发中,普通的页面提交动作,和ajax提交动作,处理方式不一样,因为跳转后直接显 ...

  8. HandlerThread源码分析

    其实原本HandlerThread的分析不应该单独开一篇博客的,应该在讲消息机制的那一片中一起分析. 但当时忘记了,而且今天第一次用MarkDown写博客,有点上瘾,就再来一篇,权当滥竽充数过过手瘾. ...

  9. JVM常量池

    常量池(constant_pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据.它包括了关于类.方法.接口等中的常量,也包括字符串常量和符号引用.运行时常量池是方法区的一部分 ...

  10. Android长时间后台运行Service

         项目需要在后台获取GPS经纬度.当用户对手机有一段时间没有操作后,屏幕(Screen)将从高亮(Bright)变为暗淡(Dim),如果再过段时间没操作, 屏幕(Screen)将又由暗淡(Di ...