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

相关文章:

  • 2022-12-23
  • 2021-04-06
  • 2022-12-23
  • 2021-10-22
  • 2021-06-19
  • 2021-07-22
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-11-07
  • 2022-12-23
  • 2021-12-24
  • 2021-10-03
相关资源
相似解决方案