打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
30种图像动画特效算法(C#多线程版)(上)
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。http://mengliao.blog.51cto.com/876134/473169
这是一个比较复杂的程序,包含了30种图像动画特效演示,使用C#编写,源程序大概2000多行。
这个软件实际上主要是四个方面的内容:
1、30种动画特效算法,包含诸如随机拉丝、交替分块、多经扫描等等。这些算法设计的比较巧妙,也就是说大量的使用了图像处理的一些技巧。
2、.NET的GDI+技术功能非常强大,本软件中几乎涉及了GDI+中的各个方面,例如仿射变换矩阵、颜色变换矩阵、块处理等等。
3、采用多线程技术,使得软件看起来比较有序,同时采用信号量来实现暂停、继续、取消等功能。
4、采用比较严谨的面向对象的程序设计技术,从类的定义到方法的、事件的定义都严格按照OOP理论完成,可以说比较完整、精确的体现了OOP精髓。
这是截屏动画效果:

由于源程序太多,所以分三次发出,这次是(上),先发前10个动画特效:
  1. using System; 
  2. using System.Drawing; 
  3. using System.Drawing.Drawing2D; 
  4. using System.Drawing.Imaging; 
  5. using System.Threading; 
  6. using System.Windows.Forms; 
  7. namespace Mengliao.CSharp.A14 
  8. {
  9.     #region  动画类型枚举
  10.     // 本例为了简单起见没有使用见名知意的名称,如用于实际可将这些枚举成员更名为准确的英文名称
  11.     enum AnimateType 
  12.     { 
  13.         Animator01, Animator02, Animator03, Animator04, Animator05, 
  14.         Animator06, Animator07, Animator08, Animator09, Animator10, 
  15.         Animator11, Animator12, Animator13, Animator14, Animator15, 
  16.         Animator16, Animator17, Animator18, Animator19, Animator20, 
  17.         Animator21, Animator22, Animator23, Animator24, Animator25, 
  18.         Animator26, Animator27, Animator28, Animator29, Animator30 
  19.     }
  20.     #endregion
  21.     class AnimatorImage 
  22.     {
  23.         #region 私有字段
  24.         // 输入位图
  25.         private Bitmap bmp; 
  26.         // 是否已经开始绘制
  27.         private bool drawStarted = false
  28.         // 在绘制过程中是否终止的自动复位信号量,有信号则终止
  29.         private AutoResetEvent cancelEvent = new AutoResetEvent(false); 
  30.         // 在绘制过程中是否暂停的手动复位信号量,有信号则暂停
  31.         private ManualResetEvent pauseEvent = new ManualResetEvent(false); 
  32.         // 输出位图的DC
  33.         private Graphics dc;
  34.         #endregion
  35.         #region 属性和事件
  36.         private Bitmap outBmp; 
  37.         /// <summary>
  38.         /// 输出位图。
  39.         /// </summary>
  40.         public Bitmap OutBmp 
  41.         { 
  42.             get { return outBmp; } 
  43.         } 
  44.         private int delay; 
  45.         /// <summary>
  46.         /// 延时系数。
  47.         /// </summary>
  48.         public int Delay 
  49.         { 
  50.             get { return delay; } 
  51.             set { delay = Math.Min(Math.Max(1, value), 100); } // 使其介于1到100之间
  52.         } 
  53.         /// <summary>
  54.         /// 重绘事件。
  55.         /// </summary>
  56.         public event PaintEventHandler Redraw; 
  57.         protected void OnRedraw(Rectangle clipRectangle) 
  58.         { 
  59.             if (Redraw != null
  60.             { 
  61.                 Redraw.Invoke(this, new PaintEventArgs(dc, clipRectangle)); 
  62.             } 
  63.         } 
  64.         /// <summary>
  65.         /// 绘制开始事件。
  66.         /// </summary>
  67.         public event EventHandler DrawStarted; 
  68.         protected void OnDrawStarted(object sender, EventArgs e) 
  69.         { 
  70.             drawStarted = true
  71.             if (DrawStarted != null
  72.             { 
  73.                 DrawStarted.Invoke(sender, e); 
  74.             } 
  75.         } 
  76.         /// <summary>
  77.         /// 绘制完成事件。
  78.         /// </summary>
  79.         public event EventHandler DrawCompleted; 
  80.         protected void OnDrawCompleted(object sender, EventArgs e) 
  81.         { 
  82.             drawStarted = false
  83.             cancelEvent.Reset(); 
  84.             if (DrawCompleted != null
  85.             { 
  86.                 DrawCompleted.Invoke(sender, e); 
  87.             } 
  88.         }
  89.         #endregion
  90.         #region 私有方法
  91.         // 在输出位图上显示绘制过程中的错误信息
  92.         private void ShowError(string errMsg) 
  93.         { 
  94.             Font font = new Font("宋体", 9); 
  95.             SizeF size = dc.MeasureString(errMsg, font); 
  96.             PointF point = new PointF((outBmp.Width - size.Width) / 2f, (outBmp.Height - size.Height) / 2f); 
  97.             // 在文字的四个方向各一个像素处绘制其它颜色的文字,以形成边框,否则可能看不清除文字
  98.             dc.DrawString(errMsg, font, Brushes.Red, point.X - 1f, point.Y); 
  99.             dc.DrawString(errMsg, font, Brushes.Red, point.X + 1f, point.Y); 
  100.             dc.DrawString(errMsg, font, Brushes.Red, point.X, point.Y - 1f); 
  101.             dc.DrawString(errMsg, font, Brushes.Red, point.X, point.Y + 1f); 
  102.             // 绘制文字
  103.             dc.DrawString(errMsg, font, Brushes.White, point); 
  104.             ShowBmp(new Rectangle(Point.Round(point), Size.Round(size))); 
  105.         } 
  106.         // 供绘制动画方法内部调用,三个重载版本
  107.         private void ShowBmp(Rectangle clipRectangle) 
  108.         { 
  109.             string cancelMsg = "绘图操作已被用户取消!"
  110.             OnRedraw(clipRectangle); 
  111.             if (cancelEvent.WaitOne(0)) // 取消
  112.             { 
  113.                 // 该异常将被外部方法捕获,即各个绘制方法
  114.                 throw new ApplicationException(cancelMsg); 
  115.             } 
  116.             while (pauseEvent.WaitOne(0)) // 暂停
  117.             { 
  118.                 if (cancelEvent.WaitOne(10)) // 在暂停期间取消
  119.                 { 
  120.                     pauseEvent.Reset(); 
  121.                     throw new ApplicationException(cancelMsg); 
  122.                 } 
  123.             } 
  124.         } 
  125.         private void ShowBmp(RectangleF clipRectangle) // 接收浮点参数
  126.         { 
  127.             ShowBmp(Rectangle.Round(clipRectangle)); 
  128.         } 
  129.         private void ShowBmp() // 重绘全部区域
  130.         { 
  131.             ShowBmp(new Rectangle(0, 0, bmp.Width, bmp.Height)); 
  132.         } 
  133.         // 清空背景
  134.         private void ClearBackground() 
  135.         { 
  136.             dc.Clear(Color.FromKnownColor(KnownColor.ButtonFace)); // 置背景色
  137.             ShowBmp(); // 重绘所有区域
  138.         }
  139.         #endregion
  140.         #region 动画控制
  141.         /// <summary>
  142.         /// 取消绘制。
  143.         /// </summary>
  144.         public void CancelDraw() 
  145.         { 
  146.             if (drawStarted) 
  147.             { 
  148.                 cancelEvent.Set(); 
  149.             } 
  150.         } 
  151.         /// <summary>
  152.         /// 暂停绘制。
  153.         /// </summary>
  154.         public void PauseDraw() 
  155.         { 
  156.             if (drawStarted) 
  157.             { 
  158.                 pauseEvent.Set(); 
  159.             } 
  160.         } 
  161.         /// <summary>
  162.         /// 继续绘制。
  163.         /// </summary>
  164.         public void ResumeDraw() 
  165.         { 
  166.             if (drawStarted) 
  167.             { 
  168.                 pauseEvent.Reset(); 
  169.             } 
  170.         }
  171.         #endregion
  172.         #region 构造函数
  173.         /// <summary>
  174.         /// 实例化后,需分配事件处理方法,所有事件均在独立线程中触发;默认延时系数为1。
  175.         /// </summary>
  176.         /// <param name="inBmp">输入位图</param>
  177.         public AnimatorImage(Bitmap inBmp) 
  178.         { 
  179.             delay = 1; 
  180.             this.bmp = (Bitmap)inBmp.Clone(); 
  181.             outBmp = new Bitmap(this.bmp.Width, this.bmp.Height); 
  182.             dc = Graphics.FromImage(outBmp); 
  183.         }
  184.         #endregion
  185.         #region 绘制动画
  186.         /// <summary>
  187.         /// 以独立线程的方式开始显示动画。
  188.         /// </summary>
  189.         /// <param name="animateType">动画类型枚举</param>
  190.         public void DrawAnimator(AnimateType animateType) 
  191.         { 
  192.             if (drawStarted) // 判断动画是否已经开始绘制
  193.             { 
  194.                 if (pauseEvent.WaitOne(0)) // 动画已开始,但被暂停了,继续
  195.                     pauseEvent.Reset(); 
  196.                 else
  197.                     pauseEvent.Set(); 
  198.                 return
  199.             } 
  200.             ThreadStart threadMethod; 
  201.             switch (animateType) 
  202.             { 
  203.                 case AnimateType.Animator01: 
  204.                     threadMethod = Animator01; 
  205.                     break
  206.                 case AnimateType.Animator02: 
  207.                     threadMethod = Animator02; 
  208.                     break
  209.                 case AnimateType.Animator03: 
  210.                     threadMethod = Animator03; 
  211.                     break
  212.                 case AnimateType.Animator04: 
  213.                     threadMethod = Animator04; 
  214.                     break
  215.                 case AnimateType.Animator05: 
  216.                     threadMethod = Animator05; 
  217.                     break
  218.                 case AnimateType.Animator06: 
  219.                     threadMethod = Animator06; 
  220.                     break
  221.                 case AnimateType.Animator07: 
  222.                     threadMethod = Animator07; 
  223.                     break
  224.                 case AnimateType.Animator08: 
  225.                     threadMethod = Animator08; 
  226.                     break
  227.                 case AnimateType.Animator09: 
  228.                     threadMethod = Animator09; 
  229.                     break
  230.                 case AnimateType.Animator10: 
  231.                     threadMethod = Animator10; 
  232.                     break
  233.                 case AnimateType.Animator11: 
  234.                     threadMethod = Animator11; 
  235.                     break
  236.                 case AnimateType.Animator12: 
  237.                     threadMethod = Animator12; 
  238.                     break
  239.                 case AnimateType.Animator13: 
  240.                     threadMethod = Animator13; 
  241.                     break
  242.                 case AnimateType.Animator14: 
  243.                     threadMethod = Animator14; 
  244.                     break
  245.                 case AnimateType.Animator15: 
  246.                     threadMethod = Animator15; 
  247.                     break
  248.                 case AnimateType.Animator16: 
  249.                     threadMethod = Animator16; 
  250.                     break
  251.                 case AnimateType.Animator17: 
  252.                     threadMethod = Animator17; 
  253.                     break
  254.                 case AnimateType.Animator18: 
  255.                     threadMethod = Animator18; 
  256.                     break
  257.                 case AnimateType.Animator19: 
  258.                     threadMethod = Animator19; 
  259.                     break
  260.                 case AnimateType.Animator20: 
  261.                     threadMethod = Animator20; 
  262.                     break
  263.                 case AnimateType.Animator21: 
  264.                     threadMethod = Animator21; 
  265.                     break
  266.                 case AnimateType.Animator22: 
  267.                     threadMethod = Animator22; 
  268.                     break
  269.                 case AnimateType.Animator23: 
  270.                     threadMethod = Animator23; 
  271.                     break
  272.                 case AnimateType.Animator24: 
  273.                     threadMethod = Animator24; 
  274.                     break
  275.                 case AnimateType.Animator25: 
  276.                     threadMethod = Animator25; 
  277.                     break
  278.                 case AnimateType.Animator26: 
  279.                     threadMethod = Animator26; 
  280.                     break
  281.                 case AnimateType.Animator27: 
  282.                     threadMethod = Animator27; 
  283.                     break
  284.                 case AnimateType.Animator28: 
  285.                     threadMethod = Animator28; 
  286.                     break
  287.                 case AnimateType.Animator29: 
  288.                     threadMethod = Animator29; 
  289.                     break
  290.                 default
  291.                     threadMethod = Animator30; 
  292.                     break
  293.             } 
  294.             Thread drawThread = new Thread(threadMethod); 
  295.             drawThread.IsBackground = true; // 设为后台线程,避免该线程未结束时退出主线程而引发异常
  296.             drawThread.Start(); 
  297.         }
  298.         #endregion
  299.         // ==========
  300.         // 动画算法
  301.         // ==========
  302.         #region 压缩反转(改进版)
  303.         // 原理:计算图像位置和高度,以高度的一半为轴进行对换上下半边的图像
  304.         private void Animator01() 
  305.         { 
  306.             const float blockSize = 8; // 每次显示的高度增量,应能被高度整除
  307.             try
  308.             { 
  309.                 OnDrawStarted(this, EventArgs.Empty); // 触发开始绘制事件
  310.                 //ClearBackground();
  311.                 Color bgColor = Color.FromKnownColor(KnownColor.ButtonFace); 
  312.                 RectangleF srcRect = new RectangleF(0, 0, bmp.Width, bmp.Height); 
  313.                 for (float i = (float)Math.Floor(-bmp.Height / blockSize); i <= Math.Ceiling(bmp.Height / blockSize); i++) 
  314.                 { 
  315.                     dc.Clear(bgColor); // 清空DC
  316.                     float j = i * blockSize / 2; 
  317.                     float destTop = bmp.Height / 2 - j; // 目标矩形的顶位置
  318.                     // 目标矩形区域在循环的前半段为垂直反向
  319.                     RectangleF destRect = new RectangleF(0, destTop, bmp.Width, 2 * j); 
  320.                     // 在指定区域绘制图像,该图像被拉伸
  321.                     dc.DrawImage(bmp, destRect, srcRect, GraphicsUnit.Pixel); 
  322.                     ShowBmp(); 
  323.                     Thread.Sleep(10 * delay); // 休眠
  324.                 } 
  325.             } 
  326.             catch (Exception ex) 
  327.             { 
  328.                 ShowError(ex.Message); 
  329.             } 
  330.             finally
  331.             { 
  332.                 OnDrawCompleted(this, EventArgs.Empty); // 触发完成绘制事件
  333.             } 
  334.         }
  335.         #endregion
  336.         #region 垂直对接(改进版)
  337.         // 原理:将图像分为上下部分,然后同时向中心移动
  338.         private void Animator02() 
  339.         { 
  340.             const int stepCount = 4; // 每次上下移动的步长像素,应能被高度整除
  341.             try
  342.             { 
  343.                 OnDrawStarted(this, EventArgs.Empty); 
  344.                 ClearBackground(); 
  345.                 Rectangle sourTopRect = new Rectangle(0, 0, bmp.Width, bmp.Height / 2); // 上半部分源区域
  346.                 Rectangle sourBottRect = new Rectangle(0, bmp.Height / 2, bmp.Width, bmp.Height / 2); // 下半部分源区域
  347.                 for (int i = 0; i <= bmp.Height / 2; i += stepCount) 
  348.                 { 
  349.                     Rectangle destTopRect = new Rectangle(0, i - bmp.Height / 2 + 1, bmp.Width, bmp.Height / 2); // 上半部分目标区域
  350.                     Rectangle destBottRect = new Rectangle(0, bmp.Height - i - 1, bmp.Width, bmp.Height / 2); // 下半部分目标区域
  351.                     dc.DrawImage(bmp, destTopRect, sourTopRect, GraphicsUnit.Pixel); 
  352. dc.DrawImage(bmp, destBottRect, sourBottRect, GraphicsUnit.Pixel);
  353.                     ShowBmp(Rectangle.Union(destTopRect, destBottRect)); 
  354.                     Thread.Sleep(10 * delay); 
  355.                 } 
  356.             } 
  357.             catch (Exception ex) 
  358.             { 
  359.                 ShowError(ex.Message); 
  360.             } 
  361.             finally
  362.             { 
  363.                 OnDrawCompleted(this, EventArgs.Empty); 
  364.             } 
  365.         }
  366.         #endregion
  367.         #region 中心闭幕(改进版)
  368.         // 原理:由大到小生成图像中心区域,然后用总区域减去该中心区域,并用材质画刷填充
  369.         private void Animator03() 
  370.         { 
  371.             const float stepCount = 4; // 每次收缩的步长像素
  372.             try
  373.             { 
  374.                 OnDrawStarted(this, EventArgs.Empty); 
  375.                 ClearBackground(); 
  376.                 // 建立空区域,如使用Region的无参构造函数则建立一个无限大小的区域,而非空区域
  377.                 Region region = new Region(new GraphicsPath()); 
  378.                 // 建立位图材质画刷
  379.                 TextureBrush textureBrush = new TextureBrush(bmp); 
  380.                 for (float x = 0; x <= bmp.Width / 2f; x += stepCount) 
  381.                 { 
  382.                     // 添加整个位图区域
  383.                     region.Union(new Rectangle(0, 0, bmp.Width, bmp.Height)); 
  384.                     // 从中心开始,由大到小填充背景色或填充缩小尺寸的原图
  385.                     // 计算高度变化量,如果宽度大,则高度变化量小于宽度,否则大于宽度
  386.                     float y = x * bmp.Height / bmp.Width; 
  387.                     RectangleF rect = new RectangleF(x, y, bmp.Width - 2f * x, bmp.Height - 2f * y); 
  388.                     // 计算整个位图区域与背景色区域的差集
  389.                     region.Exclude(rect); 
  390.                     dc.FillRegion(textureBrush, region); // 使用材质画刷填充区域
  391.                     ShowBmp(region.GetBounds(dc)); 
  392.                     Thread.Sleep(10 * delay); 
  393.                 } 
  394.                 // 由于stepCount可能无法被宽度整除,则最终生成的背景色区域并不为空,故在循环结束后绘制整个位图
  395.                 dc.DrawImage(bmp, 0, 0); 
  396.                 ShowBmp(); 
  397.             } 
  398.             catch (Exception ex) 
  399.             { 
  400.                 ShowError(ex.Message); 
  401.             } 
  402.             finally
  403.             { 
  404.                 OnDrawCompleted(this, EventArgs.Empty); 
  405.             } 
  406.         }
  407.         #endregion
  408.         #region 中心放大(改进版)
  409.         // 原理:由中心向边缘按高度和宽度的比例循环输出所有像素,直到高度和宽度为原始大小
  410.         private void Animator04() 
  411.         { 
  412.             const int stepCount = 4; // 每次增加的像素量,应能被宽度整除
  413.             try
  414.             { 
  415.                 OnDrawStarted(this, EventArgs.Empty); 
  416.                 ClearBackground(); 
  417.                 Rectangle sourRect = new Rectangle(0, 0, bmp.Width, bmp.Height); // 源区域为整个位图
  418.                 for (int i = 0; i <= bmp.Width / 2; i += stepCount) 
  419.                 { 
  420.                     int j = i * bmp.Height / bmp.Width; // 计算高度变化量,如果宽度大,则高度变化量小于宽度,否则大于宽度
  421.                     Rectangle destRect = new Rectangle(bmp.Width / 2 - i, bmp.Height / 2 - j, 2 * i, 2 * j); 
  422.                     dc.DrawImage(bmp, destRect, sourRect, GraphicsUnit.Pixel); 
  423.                     ShowBmp(destRect); 
  424.                     Thread.Sleep(10 * delay); 
  425.                 } 
  426.             } 
  427.             catch (Exception ex) 
  428.             { 
  429.                 ShowError(ex.Message); 
  430.             } 
  431.             finally
  432.             { 
  433.                 OnDrawCompleted(this, EventArgs.Empty); 
  434.             } 
  435.         }
  436.         #endregion
  437.         #region 逐行分块
  438.         // 原理:将图像分为正方形块,然后从左到右,从上到下顺序显示
  439.         private void Animator05() 
  440.         { 
  441.             const float blockSize = 50; // 正方块的边长
  442.             try
  443.             { 
  444.                 OnDrawStarted(this, EventArgs.Empty); 
  445.                 ClearBackground(); 
  446.                 // 防止最后一列、最后一行不足一块的尺寸而不显示,故采用上取整
  447.                 for (int y = 0; y < Math.Ceiling(bmp.Height / blockSize); y++) 
  448.                 { 
  449.                     for (int x = 0; x < Math.Ceiling(bmp.Width / blockSize); x++) 
  450.                     { 
  451.                         RectangleF rect; 
  452.                         if (y % 2 == 0) // 从左到右
  453.                         { 
  454.                             rect = new RectangleF(x * blockSize, y * blockSize, blockSize, blockSize); 
  455.                         } 
  456.                         else // 从右到左
  457.                         { 
  458.                             rect = new RectangleF((bmp.Width / blockSize - x - 1) * blockSize, y * blockSize, blockSize, blockSize); 
  459.                         } 
  460.                         dc.DrawImage(bmp, rect, rect, GraphicsUnit.Pixel); 
  461.                         ShowBmp(rect); 
  462.                         Thread.Sleep(10 * delay); 
  463.                     } 
  464.                 } 
  465.             } 
  466.             catch (Exception ex) 
  467.             { 
  468.                 ShowError(ex.Message); 
  469.             } 
  470.             finally
  471.             { 
  472.                 OnDrawCompleted(this, EventArgs.Empty); 
  473.             } 
  474.         }
  475.         #endregion
  476.         #region 交替分块(改进版)
  477.         // 原理:将图像分为正方形块,然后计算所有分块按照奇偶从左到右显示或从右到左显示所需的区域,并用材质画刷填充
  478.         private void Animator06() 
  479.         { 
  480.             const float blockSize = 70; // 正方块的边长
  481.             const int showWidth = 1; // 每次显示的像素列数
  482.             try
  483.             { 
  484.                 OnDrawStarted(this, EventArgs.Empty); 
  485.                 ClearBackground(); 
  486.                 // 建立空区域,如使用Region的无参构造函数则建立一个无限大小的区域,而非空区域
  487.                 Region region = new Region(new GraphicsPath()); 
  488.                 // 建立位图材质画刷
  489.                 TextureBrush textureBrush = new TextureBrush(bmp); 
  490.                 // 分块的行坐标+列坐标为偶数则从左到右逐列显示本块,否则从右到左逐列显示本块
  491.                 for (int i = 0; i <= Math.Ceiling(blockSize / showWidth); i++) 
  492.                 { 
  493.                     for (int x = 0; x < Math.Ceiling(bmp.Width / blockSize); x++) 
  494.                     { 
  495.                         for (int y = 0; y < Math.Ceiling(bmp.Height / blockSize); y++) 
  496.                         { 
  497.                             RectangleF rect; 
  498.                             // 判断块的行列坐标和为奇数或偶数
  499.                             if ((x + y) % 2 == 0) 
  500.                             { 
  501.                                 rect = new RectangleF(x * blockSize + i * showWidth, y * blockSize, showWidth, blockSize); 
  502.                             } 
  503.                             else
  504.                             { 
  505.                                 rect = new RectangleF((x + 1) * blockSize - i * showWidth, y * blockSize, showWidth, blockSize); 
  506.                             } 
  507.                             region.Union(rect); // 将要显示的区域合并到region中
  508.                         } 
  509.                     } 
  510.                     dc.FillRegion(textureBrush, region); // 使用材质画刷填充区域
  511.                     ShowBmp(region.GetBounds(dc)); 
  512.                     Thread.Sleep(10 * delay); 
  513.                 } 
  514.             } 
  515.             catch (Exception ex) 
  516.             { 
  517.                 ShowError(ex.Message); 
  518.             } 
  519.             finally
  520.             { 
  521.                 OnDrawCompleted(this, EventArgs.Empty); 
  522.             } 
  523.         }
  524.         #endregion
  525.         #region 交叉竖条(改进版)
  526.         // 原理:将图像分成宽度相等的列,然后计算从上下两个方向交叉前进的区域,并使用材质画刷填充
  527.         private void Animator07() 
  528.         { 
  529.             const float lineWidth = 4; // 竖条宽度
  530.             const float lineStep = 6; // 竖条每次前进的步长
  531.             try
  532.             { 
  533.                 OnDrawStarted(this, EventArgs.Empty); 
  534.                 ClearBackground(); 
  535.                 GraphicsPath path = new GraphicsPath(); // 建立路径,路径处理速度要明显快于Region,但不支持集合运算
  536.                 TextureBrush textureBrush = new TextureBrush(bmp); 
  537.                 // 从上到下和从下到上以步长为单位显示
  538.                 for (int y = 0; y < Math.Ceiling(bmp.Height / lineStep); y++) 
  539.                 { 
  540.                     // 显示两个方向的每个垂直竖条
  541.                     for (int x = 0; x < Math.Ceiling(bmp.Width / lineWidth); x++) 
  542.                     { 
  543.                         RectangleF rect; 
  544.                         if (x % 2 == 0) // 从上到下
  545.                         { 
  546.                             rect = new RectangleF(x * lineWidth, y * lineStep, lineWidth, lineStep); 
  547.                         } 
  548.                         else // 从下到上
  549.                         { 
  550.                             rect = new RectangleF(x * lineWidth, bmp.Height - y * lineStep - lineStep, lineWidth, lineStep); 
  551.                         } 
  552.                         path.AddRectangle(rect); 
  553.                     } 
  554.                     dc.FillPath(textureBrush, path); 
  555.                     ShowBmp(path.GetBounds()); 
  556.                     Thread.Sleep(10 * delay); 
  557.                 } 
  558.             } 
  559.             catch (Exception ex) 
  560.             { 
  561.                 ShowError(ex.Message); 
  562.             } 
  563.             finally
  564.             { 
  565.                 OnDrawCompleted(this, EventArgs.Empty); 
  566.             } 
  567.         }
  568.         #endregion
  569.         #region 透明淡入(改进版)
  570.         // 原理:使用ImageAttributes类和颜色转换矩阵处理图像,使每个像素的颜色分量同步增加
  571.         private void Animator08() 
  572.         { 
  573.             const float stepCount = 0.02f; // 颜色转换矩阵增量,该值除1应等于整数
  574.             try
  575.             { 
  576.                 OnDrawStarted(this, EventArgs.Empty); 
  577.                 ClearBackground(); 
  578.                 // ImageAttributes类的实例用于调整颜色,由DrawImage()方法调用
  579.                 ImageAttributes attributes = new ImageAttributes(); 
  580.                 // 建立5*5阶RGBA颜色矩阵
  581.                 ColorMatrix matrix = new ColorMatrix(); 
  582.                 float value = 0; 
  583.                 while (value < 1f) 
  584.                 { 
  585.                     matrix.Matrix33 = value; 
  586.                     // 为ImageAttributes对象指定颜色调整矩阵
  587.                     // ColorMatrixFlag.Default表示使用矩阵调整所有颜色;ColorAdjustType.Bitmap表示调整位图的颜色
  588.                     attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); 
  589.                     dc.Clear(Color.FromKnownColor(KnownColor.ButtonFace)); // 清空DC,否则每次会将不同的透明度图像叠加显示
  590.                     dc.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes); 
  591.                     value += stepCount; 
  592.                     ShowBmp(); 
  593.                     Thread.Sleep(10 * delay); 
  594.                 } 
  595.             } 
  596.             catch (Exception ex) 
  597.             { 
  598.                 ShowError(ex.Message); 
  599.             } 
  600.             finally
  601.             { 
  602.                 OnDrawCompleted(this, EventArgs.Empty); 
  603.             } 
  604.         }
  605.         #endregion
  606.         #region 三色淡入
  607.         // 原理:使用ImageAttributes类和颜色转换矩阵处理图像,分三次增加每个像素的单个颜色分量
  608.         private void Animator09() 
  609.         { 
  610.             const float stepCount = 0.025f; // 颜色转换矩阵增量,该值除1应等于整数
  611.             try
  612.             { 
  613.                 OnDrawStarted(this, EventArgs.Empty); 
  614.                 ClearBackground(); 
  615.                 // ImageAttributes类的实例用于调整颜色,由DrawImage()方法调用
  616.                 ImageAttributes attributes = new ImageAttributes(); 
  617.                 // 建立5*5阶RGBA颜色矩阵
  618.                 ColorMatrix matrix = new ColorMatrix(); 
  619.                 matrix.Matrix00 = 0f; // R为0
  620.                 matrix.Matrix11 = 0f; // G为0
  621.                 matrix.Matrix22 = 0f; // B为0
  622.                 // 以下三个循环依次处理B、R、G,符合亮度方程的原理
  623.                 // 人眼对B最不敏感,对G最敏感,或者说B传达的亮度信息最少,G传达的亮度信息最多
  624.                 // 因此先处理亮度信息少的,最后处理亮度信息多的,如果反过来处理,则变化不明显
  625.                 float value = 0f; 
  626.                 while (value < 1f) 
  627.                 { 
  628.                     matrix.Matrix22 = value; // 颜色R的转换矩阵分量值
  629.                     // 为ImageAttributes对象指定颜色调整矩阵
  630.                     // ColorMatrixFlag.Default表示使用矩阵调整所有颜色;ColorAdjustType.Bitmap表示调整位图的颜色
  631.                     attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); 
  632.                     dc.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes); 
  633.                     value += stepCount; 
  634.                     ShowBmp(); 
  635.                     Thread.Sleep(10 * delay); 
  636.                 } 
  637.                 value = stepCount; 
  638.                 while (value < 1f) 
  639.                 { 
  640.                     matrix.Matrix00 = value; // 颜色G的转换矩阵分量值
  641.                     attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); 
  642.                     dc.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes); 
  643.                     value += stepCount; 
  644.                     ShowBmp(); 
  645.                     Thread.Sleep(10 * delay); 
  646.                 } 
  647.                 value = stepCount; 
  648.                 while (value < 1f) 
  649.                 { 
  650.                     matrix.Matrix11 = value; // 颜色B的转换矩阵分量值
  651.                     attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap); 
  652.                     dc.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes); 
  653.                     value += stepCount; 
  654.                     ShowBmp(); 
  655.                     Thread.Sleep(10 * delay); 
  656.                 } 
  657.             } 
  658.             catch (Exception ex) 
  659.             { 
  660.                 ShowError(ex.Message); 
  661.             } 
  662.             finally
  663.             { 
  664.                 OnDrawCompleted(this, EventArgs.Empty); 
  665.             } 
  666.         }
  667.         #endregion
  668.         #region 水平拉幕
  669.         // 原理:由中心向开始逐渐输出中心两侧的像素,直到宽度为原始大小
  670.         private void Animator10() 
  671.         { 
  672.             const int stepCount = 4; // 每次增加的步长像素,该值应能被宽度整除
  673.             try
  674.             { 
  675.                 OnDrawStarted(this, EventArgs.Empty); 
  676.                 ClearBackground(); 
  677.                 for (int i = 0; i <= Math.Ceiling(bmp.Width / 2f); i += stepCount) 
  678.                 { 
  679.                     Rectangle rect = new Rectangle(bmp.Width / 2 - i, 0, 2 * i, bmp.Height); 
  680.                     dc.DrawImage(bmp, rect, rect, GraphicsUnit.Pixel); 
  681.                     ShowBmp(rect); 
  682.                     Thread.Sleep(10 * delay); 
  683.                 } 
  684.             } 
  685.             catch (Exception ex) 
  686.             { 
  687.                 ShowError(ex.Message); 
  688.             } 
  689.             finally
  690.             { 
  691.                 OnDrawCompleted(this, EventArgs.Empty); 
  692.             } 
  693.         }
  694.         #endregion

本文的最后一部分(下),会附上完整的项目文件组,包含所有资源及可执行文件。
这里是本文的第二部分:http://mengliao.blog.51cto.com/876134/473193

本文出自 “梦辽软件工作室” 博客,请务必保留此出处http://mengliao.blog.51cto.com/876134/473169

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Visual C Examples - Displaying a Bitmap
C# 图片格式转换的实例代码
C语言打造——游戏场景里面的人物行走
C#自动生成漂亮的水晶效果头像
c#GDI+游戏编程:《疯狂的炸弹之幽灵之战v1.0》角色动画、绘制、走动 . | 学步园
php上传文件
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服