File: commonui\System\Drawing\ImageInfo.cs
Project: ndp\fx\src\System.Drawing.csproj (System.Drawing)
//------------------------------------------------------------------------------
// <copyright file="ImageInfo.cs" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>                                                                
//------------------------------------------------------------------------------
namespace System.Drawing {
    using System.Threading;
 
    using System;
    using System.Diagnostics;
    using System.Drawing.Imaging;
 
    /// <devdoc>
    ///     Animates one or more images that have time-based frames.
    ///     This file contains the nested ImageInfo class - See ImageAnimator.cs for the definition of the outer class.
    /// </devdoc>                                   
    public sealed partial class ImageAnimator {
        /// <devdoc> 
        ///     ImageAnimator nested helper class used to store extra image state info.
        /// </devdoc>  
        private class ImageInfo {
            const int PropertyTagFrameDelay = 0x5100;
 
            Image image;
            int frame;
            int frameCount;
            bool frameDirty;
            bool animated;
            EventHandler onFrameChangedHandler;
            int[] frameDelay;
            int frameTimer;
 
            /// <devdoc> 
            /// </devdoc>  
            public ImageInfo(Image image) {
                this.image = image;
                animated = ImageAnimator.CanAnimate(image);
 
                if (animated) {
                    frameCount = image.GetFrameCount(FrameDimension.Time);
 
                    PropertyItem frameDelayItem = image.GetPropertyItem(PropertyTagFrameDelay);
 
                    // If the image does not have a frame delay, we just return 0.                                     
                    //
                    if (frameDelayItem != null) {
                        // Convert the frame delay from byte[] to int
                        //
                        byte[] values = frameDelayItem.Value;
                        Debug.Assert(values.Length == 4 * FrameCount, "PropertyItem has invalid value byte array");
                        frameDelay = new int[FrameCount];
                        for (int i=0; i < FrameCount; ++i) {
                            frameDelay[i] = values[i * 4] + 256 * values[i * 4 + 1] + 256 * 256 * values[i * 4 + 2] + 256 * 256 * 256 * values[i * 4 + 3];
                        }
                    }
                }
                else {
                    frameCount = 1;
                }
                if (frameDelay == null) {
                    frameDelay = new int[FrameCount];
                }
            }                                               
 
            /// <devdoc> 
            ///     Whether the image supports animation.
            /// </devdoc>  
            public bool Animated {
                get {
                    return animated;
                }
            }
 
            /// <devdoc> 
            ///     The current frame.
            /// </devdoc> 
            public int Frame {
                get {
                    return frame;
                }                
                set {
                    if (frame != value) {
                        if (value < 0 || value >= FrameCount) {
                            throw new ArgumentException(SR.GetString(SR.InvalidFrame), "value");
                        }
 
                        if (Animated) {
                            frame = value;
                            frameDirty = true;
 
                            OnFrameChanged(EventArgs.Empty);
                        }
                    }
                }
            }
 
            /// <devdoc> 
            ///     The current frame has not been updated.
            /// </devdoc> 
            public bool FrameDirty {
                get {
                    return frameDirty;
                }
            }
 
            /// <devdoc> 
            /// </devdoc> 
            public EventHandler FrameChangedHandler {
                get {
                    return onFrameChangedHandler;
                }
                set {
                    onFrameChangedHandler = value;
                }
            }
 
            /// <devdoc> 
            ///     The number of frames in the image.
            /// </devdoc> 
            public int FrameCount {
                get {
                    return frameCount;
                }
            }
 
            /// <devdoc> 
            ///     The delay associated with the frame at the specified index.
            /// </devdoc> 
            public int FrameDelay(int frame) {
                return frameDelay[frame];
            }
 
            /// <devdoc> 
            /// </devdoc> 
            internal int FrameTimer {
                get {
                    return frameTimer;
                }
                set {
                    frameTimer = value;
                }
            }
 
            /// <devdoc> 
            ///     The image this object wraps.
            /// </devdoc> 
            internal Image Image {
                get {
                    return image;                
                }
            }
 
            /// <devdoc> 
            ///     Selects the current frame as the active frame in the image.
            /// </devdoc> 
            internal void UpdateFrame() {
                if (frameDirty) {
                    image.SelectActiveFrame(FrameDimension.Time, Frame);
                    frameDirty = false;
                }
            }
 
            /// <devdoc> 
            ///     Raises the FrameChanged event.
            /// </devdoc> 
            protected void OnFrameChanged(EventArgs e) {
                if( this.onFrameChangedHandler != null ){
                    this.onFrameChangedHandler(image, e);
                }
            }
        }
    }
}