using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.Runtime.InteropServices; using Microsoft.Drawing; namespace Microsoft.Windows.Forms.Animate { /// /// 图片颜色切换动画 /// public sealed class UIImageAnimation : Animation { /// /// 默认动画是否随机 /// public const bool DEFAULT_ANIMATION_RANDOM_PLAY = false; /// /// 默认动画执行时间,毫秒 /// public const int DEFAULT_ANIMATION_SPAN = 3000; /// /// 空索引 /// public const int NONE_INDEX = -1; private List m_Origins = new List(); //原始图片集合 private List m_Frames = new List(); //截至帧集合 private AnimationOperations m_SuspendedOps = new AnimationOperations(); //挂起的操作 private RandomColor m_RandomColor = new RandomColor(); //随机颜色生成器 private Random m_Random = new Random(unchecked((int)DateTime.Now.Ticks)); //随机数生成器 private byte[] m_From; //起始帧数据 private int m_ToIndex = NONE_INDEX; //截至帧索引 private bool m_CurrentValid; //当前帧是否有效 #region 属性 private bool m_RandomPlay = DEFAULT_ANIMATION_RANDOM_PLAY; /// /// 获取或设置是否随机播放 /// public bool RandomPlay { get { return this.m_RandomPlay; } set { this.m_RandomPlay = value; } } private Size m_Size = new Size(1, 1); /// /// 获取或设置动画大小 /// public Size Size { get { return this.m_Size; } set { if (value.Width <= 0) value.Width = 1; if (value.Height <= 0) value.Height = 1; this.Resize(value); } } private Bitmap m_Current; /// /// 获取当前帧图像 /// public override unsafe Bitmap Current { get { //已停止 if (this.Stopped) { if (!this.m_CurrentValid) { byte[] current = this.UpdateCurrent(); if (current != null) CopyBitmap(current, this.m_Current); this.m_CurrentValid = true; } return this.m_Current; } //计算信息 byte[] from = this.m_From; byte[] to = this.m_ToIndex == NONE_INDEX ? null : this.m_Frames[this.m_ToIndex]; //图像处理 BlendBitmap(from, to, this.m_Current, this.Percentage); this.m_CurrentValid = true; return this.m_Current; } } #endregion 属性 #region 构造函数 /// /// 构造函数 /// public UIImageAnimation() { base.Span = DEFAULT_ANIMATION_SPAN; } #endregion #region 动画操作 /// /// 动画停止状态,当前帧无效时重新获取当前帧数据 /// /// 帧数据 private byte[] UpdateCurrent() { int count = this.m_Origins.Count; switch (count) { case 0: this.m_ToIndex = NONE_INDEX; return null; case 1: this.m_ToIndex = 0; return this.m_Frames[0]; default: if (this.m_ToIndex < 0 || this.m_ToIndex >= count) this.m_ToIndex = this.GetNextIndex(); return this.m_Frames[this.m_ToIndex]; } } /// /// 获取下一个目标帧 /// /// 下一个目标帧 private int GetNextIndex() { int count = this.m_Origins.Count; if (this.m_RandomPlay) { int current = this.m_ToIndex; int temp; do { temp = this.m_Random.Next(count); } while (temp == current); return temp; } else { return (this.m_ToIndex + 1 >= count) ? 0 : (this.m_ToIndex + 1); } } /// /// 切换下一帧,开始动画 /// public void Next() { //动画未结束 if (!this.Stopped) return; //恢复挂起的操作,截止帧变起始帧 this.Resume(); //查找下一个截止帧 switch (this.m_Origins.Count) { case 0: this.m_ToIndex = NONE_INDEX; break; case 1: this.m_ToIndex = 0; break; default: this.m_ToIndex = this.GetNextIndex(); break; } //开始动画 this.Start(); } #endregion #region 集合操作 /// /// 恢复大小改变操作,重新创建所有帧 /// private void ResumeResize(Size size) { //赋值 this.m_Size = size; //重新创建关键帧 this.m_Frames.Clear(); foreach (AnimationFrame frame in this.m_Origins) this.m_Frames.Add(GetFrameData(frame, size)); //重新创建当前图像 if (this.m_Current != null) this.m_Current.Dispose(); this.m_Current = new Bitmap(this.m_Size.Width < 1 ? 1 : this.m_Size.Width, this.m_Size.Height < 1 ? 1 : this.m_Size.Height, PixelFormat.Format32bppArgb); this.m_CurrentValid = false; } /// /// 恢复添加关键帧操作 /// /// 关键帧 private void ResumeAddFrame(AnimationFrame frame) { this.m_Origins.Add(frame); this.m_Frames.Add(GetFrameData(frame, this.m_Size)); } /// /// 恢复清空关键帧操作 /// private void ResumeClearFrame() { foreach (AnimationFrame frame in this.m_Origins) frame.Dispose(); this.m_Origins.Clear(); this.m_Frames.Clear(); } /// /// 恢复挂起的操作,截止帧变起始帧 /// private void Resume() { //截止帧变起始帧 bool getLater = false; if (this.m_ToIndex == NONE_INDEX) { this.m_From = null; } else if (this.m_SuspendedOps.Resized) { if (this.m_SuspendedOps.Cleared) this.m_From = GetFrameData(this.m_Origins[this.m_ToIndex], this.m_SuspendedOps.Size); else getLater = true; } else { this.m_From = this.m_Frames[this.m_ToIndex]; } //清理帧 if (this.m_SuspendedOps.Cleared) this.ResumeClearFrame(); //大小改变 if (this.m_SuspendedOps.Resized) this.ResumeResize(this.m_SuspendedOps.Size); //大小改变后获取 if (getLater) this.m_From = this.m_Frames[this.m_ToIndex]; //添加帧 foreach (AnimationFrame frame in this.m_SuspendedOps) this.ResumeAddFrame(frame); //清空操作 this.m_SuspendedOps.Clear(); } #endregion #region 用户操作 /// /// 大小改变 /// /// 大小 private void Resize(Size size) { if (this.m_Current == null) this.ResumeResize(size); else this.m_SuspendedOps.Resize(size); } /// /// 添加一个图像帧 /// /// 图像 public void AddFrame(Image image) { if (image == null) throw new ArgumentNullException("image"); AnimationFrame frame = new AnimationFrame(image); if (this.m_SuspendedOps.Cleared) this.m_SuspendedOps.AddFrame(frame); else this.ResumeAddFrame(frame); } /// /// 添加一个颜色帧 /// /// 颜色 public void AddFrame(Color color) { AnimationFrame frame = new AnimationFrame(color); if (this.m_SuspendedOps.Cleared) this.m_SuspendedOps.AddFrame(frame); else this.ResumeAddFrame(frame); } /// /// 添加一个随机颜色帧 /// public void AddFrame() { AnimationFrame frame = new AnimationFrame(this.m_RandomColor.Next()); if (this.m_SuspendedOps.Cleared) this.m_SuspendedOps.AddFrame(frame); else this.ResumeAddFrame(frame); } /// /// 清空所有帧,并释放占用的资源 /// public void ClearFrame() { this.m_SuspendedOps.ClearFrame(); } #endregion #region 图像处理 /// /// 从颜色创建帧数据 /// /// 颜色 /// 帧大小 /// 帧数据 private unsafe static void CopyColor(Color color, Size destSize, ref byte[] destData) { if (destData == null) destData = new byte[destSize.Width * destSize.Height * 4]; byte b = color.B; byte g = color.G; byte r = color.R; byte a = color.A; for (int i = 0, length = destData.Length; i < length; i += 4) { destData[i] = b; destData[i + 1] = g; destData[i + 2] = r; destData[i + 3] = a; } } /// /// 从图像创建帧数据 /// /// 源图像 /// 目标帧数据 private static void CopyBitmap(Bitmap srcBmp, ref byte[] destData) { if (destData == null) destData = new byte[srcBmp.Width * srcBmp.Height * 4]; using (LockedBitmapData bmpData = new LockedBitmapData(srcBmp, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb)) Marshal.Copy(bmpData.Scan0, destData, 0, destData.Length); } /// /// 从帧数据快照图像 /// /// 源帧数据 /// 目标图像 private static void CopyBitmap(byte[] srcData, Bitmap destBmp) { using (LockedBitmapData bmpData = new LockedBitmapData(destBmp, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)) Marshal.Copy(srcData, 0, bmpData.Scan0, srcData.Length); } /// /// 获取两个帧之间指定百分比的动画帧 /// /// 起始帧数据 /// 截止帧数据 /// 目标图像 /// 百分比 private unsafe static void BlendBitmap(byte[] from, byte[] to, Bitmap destBmp, double percentage) { using (LockedBitmapData bmpData = new LockedBitmapData(destBmp, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)) { if (from == null) { if (to == null) { byte* ptr = (byte*)bmpData.Scan0; for (int i = 0, length = bmpData.Stride * bmpData.Height; i < length; i++) *(ptr++) = 0; } else if (percentage == STOPPED) { Marshal.Copy(to, 0, bmpData.Scan0, to.Length); } else { byte* ptr = (byte*)bmpData.Scan0; for (int i = 0, length = to.Length; i < length; i++) *(ptr++) = (byte)(to[i] * percentage); } } else { if (to == null) { percentage = STOPPED - percentage; byte* ptr = (byte*)bmpData.Scan0; for (int i = 0, length = from.Length; i < length; i++) *(ptr++) = (byte)(from[i] * percentage); } else if (percentage == STOPPED) { Marshal.Copy(to, 0, bmpData.Scan0, from.Length); } else { byte tmp; byte* ptr = (byte*)bmpData.Scan0; for (int i = 0, length = from.Length; i < length; i++) *(ptr++) = (byte)((tmp = from[i]) + (to[i] - tmp) * percentage); } } } } /// /// 获取帧数据 /// /// 原始帧 /// 帧数据图像大小 /// 帧数据 private static byte[] GetFrameData(AnimationFrame frame, Size size) { byte[] frameData = null; switch (frame.FrameType) { case AnimationFrameType.Image: using (Bitmap bmp = new Bitmap((Image)frame.Value, size.Width, size.Height)) CopyBitmap(bmp, ref frameData); return frameData; case AnimationFrameType.Color: CopyColor((Color)frame.Value, size, ref frameData); return frameData; default: throw new ArgumentException("frame type error."); } } #endregion #region 释放资源 /// /// 释放资源 /// /// 释放托管资源为true,否则为false protected override void Dispose(bool disposing) { if (this.m_Origins != null) { foreach (AnimationFrame frame in this.m_Origins) frame.Dispose(); this.m_Origins.Clear(); this.m_Origins = null; } if (this.m_Frames != null) { this.m_Frames.Clear(); this.m_Frames = null; } if (this.m_SuspendedOps != null) { this.m_SuspendedOps.Dispose(); this.m_SuspendedOps = null; } if (this.m_Current != null) { this.m_Current.Dispose(); this.m_Current = null; } this.m_RandomColor = null; this.m_Random = null; this.m_From = null; } #endregion } }