/// <summary> /// Initializes a new instance of the <see cref="T:DesktopSprites.SpriteManagement.AnimatedImage`1"/> class from a given file. /// </summary> /// <param name="path">The path to the file which contains the image to be loaded.</param> /// <param name="staticImageFactory">The method that creates a TFrame object for a non-GIF file.</param> /// <param name="frameFactory">The method used to construct a TFrame object for each frame in a GIF animation.</param> /// <param name="allowableDepths">The allowable set of depths for the raw buffer. Use as many as your output format permits. The /// Indexed8Bpp format is required.</param> public AnimatedImage(string path, Func <string, T> staticImageFactory, BufferToImage <T> frameFactory, BitDepths allowableDepths) { FilePath = path; if (Path.GetExtension(path) == ".gif") { AnimatedImageFromGif(frameFactory, allowableDepths); } else { AnimatedImageFromStaticFormat(staticImageFactory); } }
/// <summary> /// Creates an <see cref="T:DesktopSprites.SpriteManagement.AnimatedImage`1"/> from a GIF file. /// </summary> /// <param name="frameFactory">The method used to construct a TFrame object for each frame in a GIF animation.</param> /// <param name="allowableDepths">The allowable set of depths for the raw buffer. Use as many as your output format permits. The /// Indexed8Bpp format is required.</param> private void AnimatedImageFromGif(BufferToImage <T> frameFactory, BitDepths allowableDepths) { GifImage <T> gifImage; using (FileStream imageStream = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read)) gifImage = new GifImage <T>(imageStream, frameFactory, allowableDepths); Size = gifImage.Size; LoopCount = gifImage.Iterations; ImageDuration = gifImage.Duration; int frameCount = gifImage.Frames.Length; var framesList = new List <T>(frameCount); var durationsList = new List <int>(frameCount); var frameIndexesList = new List <int>(frameCount); var frameHashesList = new List <int>(frameCount); for (int sourceFrame = 0; sourceFrame < frameCount; sourceFrame++) { int frameDuration = gifImage.Frames[sourceFrame].Duration; // Decoding the GIF may have produced frames of zero duration, we can safely drop these. // If the file has all-zero durations, we're into the land of undefined behavior for animations. // If we get to the last frame and we have nothing so far, we'll use that just so there is something to display. // Alternatively, in an image with only one frame, then only this frame ever need be displayed. if (frameDuration == 0 && !(ImageDuration == 0 && sourceFrame == frameCount - 1)) { // Dispose of unused frame. IDisposable disposable = gifImage.Frames[sourceFrame].Image as IDisposable; if (disposable != null) { disposable.Dispose(); } continue; } durationsList.Add(frameDuration); // Determine if all frames share the same duration. if (sourceFrame == 0) { commonFrameDuration = frameDuration; } else if (commonFrameDuration != frameDuration) { commonFrameDuration = -1; } // Calculate the frame hash to check if a duplicate frame exists. // This will update our collection and given hash list appropriately. AddOrReuseFrame(gifImage.Frames[sourceFrame], framesList, frameIndexesList, frameHashesList); } frames = framesList.ToImmutableArray(); if (frames.Length != frameIndexesList.Count) { frameIndexes = frameIndexesList.ToImmutableArray(); } if (commonFrameDuration == -1) { durations = durationsList.ToImmutableArray(); } }