转载 http://www.cnblogs.com/xiamojinnian/p/5007880.html
UserControl http://www.cnblogs.com/shuang121/archive/2013/01/09/2853591.html
<UserControl x:Class="WPF_Test01.LoadGifControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:GIfImageApplication"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<local:GifImage Source="../Resource/1.gif" ></local:GifImage>
</Grid>
</UserControl>
引入UserControl
<Window x:Class="WPF_Test01.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:WPF_Test01"
Title="MainWindow" Height="350" Width="525">
<Grid>
<my:LoadGifControl HorizontalAlignment="Left" Margin="300,46,0,0" x:Name="userControl11" VerticalAlignment="Top" Height="183" Width="144" />
</Grid>
</Window>
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows;
namespace GIfImageApplication { public class GifImageExceptionRoutedEventArgs : RoutedEventArgs {
public Exception ErrorException;
public GifImageExceptionRoutedEventArgs(RoutedEvent routedEvent, object obj)
: base(routedEvent, obj) {
}
} }
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; using System.Windows.Controls; using System.Windows; using System.Windows.Media; using System.Net; using System.Windows.Threading; using System.Security; using System.Windows.Resources; using System.Windows.Media.Imaging;
namespace GIfImageApplication {
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();
}
}
}
}
}