30種圖像動畫特效算法(C#多線程版)(上)

    這是一個比較複雜的程序,包含了30種圖像動畫特效演示,使用C#編寫,源程序大概2000多行。
    這個軟件實際上主要是四個方面的內容:
    一、30種動畫特效算法,包含諸如隨機拉絲、交替分塊、多經掃描等等。這些算法設計的比較巧妙,也就是說大量的使用了圖像處理的一些技巧。
    二、.NET的GDI+技術功能很是強大,本軟件中幾乎涉及了GDI+中的各個方面,例如仿射變換矩陣、顏色變換矩陣、塊處理等等。
    三、採用多線程技術,使得軟件看起來比較有序,同時採用信號量來實現暫停、繼續、取消等功能。
    四、採用比較嚴謹的面向對象的程序設計技術,從類的定義到方法的、事件的定義都嚴格按照OOP理論完成,能夠說比較完整、精確的體現了OOP精髓。
    這是截屏動畫效果:
 
    因爲源程序太多,因此分三次發出,此次是(上),先發前10個動畫特效: php

  
  
  
  
  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.  
  8. namespace Mengliao.CSharp.A14  
  9. {  
  10.     #region  動畫類型枚舉  
  11.  
  12.     // 本例爲了簡單起見沒有使用見名知意的名稱,如用於實際可將這些枚舉成員改名爲準確的英文名稱  
  13.     enum AnimateType  
  14.     {  
  15.         Animator01, Animator02, Animator03, Animator04, Animator05,  
  16.         Animator06, Animator07, Animator08, Animator09, Animator10,  
  17.         Animator11, Animator12, Animator13, Animator14, Animator15,  
  18.         Animator16, Animator17, Animator18, Animator19, Animator20,  
  19.         Animator21, Animator22, Animator23, Animator24, Animator25,  
  20.         Animator26, Animator27, Animator28, Animator29, Animator30  
  21.     }  
  22.  
  23.     #endregion  
  24.  
  25.     class AnimatorImage  
  26.     {  
  27.         #region 私有字段  
  28.  
  29.         // 輸入位圖  
  30.         private Bitmap bmp;  
  31.         // 是否已經開始繪製  
  32.         private bool drawStarted = false;  
  33.  
  34.         // 在繪製過程當中是否終止的自動復位信號量,有信號則終止  
  35.         private AutoResetEvent cancelEvent = new AutoResetEvent(false);  
  36.  
  37.         // 在繪製過程當中是否暫停的手動復位信號量,有信號則暫停  
  38.         private ManualResetEvent pauseEvent = new ManualResetEvent(false);  
  39.  
  40.         // 輸出位圖的DC  
  41.         private Graphics dc;  
  42.  
  43.         #endregion  
  44.  
  45.         #region 屬性和事件  
  46.  
  47.         private Bitmap outBmp;  
  48.         /// <summary>  
  49.         /// 輸出位圖。  
  50.         /// </summary>  
  51.         public Bitmap OutBmp  
  52.         {  
  53.             get { return outBmp; }  
  54.         }  
  55.  
  56.         private int delay;  
  57.         /// <summary>  
  58.         /// 延時係數。  
  59.         /// </summary>  
  60.         public int Delay  
  61.         {  
  62.             get { return delay; }  
  63.             set { delay = Math.Min(Math.Max(1, value), 100); } // 使其介於1到100之間  
  64.         }  
  65.  
  66.         /// <summary>  
  67.         /// 重繪事件。  
  68.         /// </summary>  
  69.         public event PaintEventHandler Redraw;  
  70.         protected void OnRedraw(Rectangle clipRectangle)  
  71.         {  
  72.             if (Redraw != null)  
  73.             {  
  74.                 Redraw.Invoke(thisnew PaintEventArgs(dc, clipRectangle));  
  75.             }  
  76.         }  
  77.  
  78.         /// <summary>  
  79.         /// 繪製開始事件。  
  80.         /// </summary>  
  81.         public event EventHandler DrawStarted;  
  82.         protected void OnDrawStarted(object sender, EventArgs e)  
  83.         {  
  84.             drawStarted = true;  
  85.             if (DrawStarted != null)  
  86.             {  
  87.                 DrawStarted.Invoke(sender, e);  
  88.             }  
  89.         }  
  90.  
  91.         /// <summary>  
  92.         /// 繪製完成事件。  
  93.         /// </summary>  
  94.         public event EventHandler DrawCompleted;  
  95.         protected void OnDrawCompleted(object sender, EventArgs e)  
  96.         {  
  97.             drawStarted = false;  
  98.             cancelEvent.Reset();  
  99.             if (DrawCompleted != null)  
  100.             {  
  101.                 DrawCompleted.Invoke(sender, e);  
  102.             }  
  103.         }  
  104.  
  105.         #endregion  
  106.  
  107.         #region 私有方法  
  108.  
  109.         // 在輸出位圖上顯示繪製過程當中的錯誤信息  
  110.         private void ShowError(string errMsg)  
  111.         {  
  112.             Font font = new Font("宋體", 9);  
  113.             SizeF size = dc.MeasureString(errMsg, font);  
  114.             PointF point = new PointF((outBmp.Width - size.Width) / 2f, (outBmp.Height - size.Height) / 2f);  
  115.             // 在文字的四個方向各一個像素處繪製其它顏色的文字,以造成邊框,不然可能看不清除文字  
  116.             dc.DrawString(errMsg, font, Brushes.Red, point.X - 1f, point.Y);  
  117.             dc.DrawString(errMsg, font, Brushes.Red, point.X + 1f, point.Y);  
  118.             dc.DrawString(errMsg, font, Brushes.Red, point.X, point.Y - 1f);  
  119.             dc.DrawString(errMsg, font, Brushes.Red, point.X, point.Y + 1f);  
  120.             // 繪製文字  
  121.             dc.DrawString(errMsg, font, Brushes.White, point);  
  122.             ShowBmp(new Rectangle(Point.Round(point), Size.Round(size)));  
  123.         }  
  124.  
  125.         // 供繪製動畫方法內部調用,三個重載版本  
  126.         private void ShowBmp(Rectangle clipRectangle)  
  127.         {  
  128.             string cancelMsg = "繪圖操做已被用戶取消!";  
  129.             OnRedraw(clipRectangle);  
  130.             if (cancelEvent.WaitOne(0)) // 取消  
  131.             {  
  132.                 // 該異常將被外部方法捕獲,即各個繪製方法  
  133.                 throw new ApplicationException(cancelMsg);  
  134.             }  
  135.             while (pauseEvent.WaitOne(0)) // 暫停  
  136.             {  
  137.                 if (cancelEvent.WaitOne(10)) // 在暫停期間取消  
  138.                 {  
  139.                     pauseEvent.Reset();  
  140.                     throw new ApplicationException(cancelMsg);  
  141.                 }  
  142.             }  
  143.         }  
  144.         private void ShowBmp(RectangleF clipRectangle) // 接收浮點參數  
  145.         {  
  146.             ShowBmp(Rectangle.Round(clipRectangle));  
  147.         }  
  148.         private void ShowBmp() // 重繪所有區域  
  149.         {  
  150.             ShowBmp(new Rectangle(0, 0, bmp.Width, bmp.Height));  
  151.         }  
  152.  
  153.         // 清空背景  
  154.         private void ClearBackground()  
  155.         {  
  156.             dc.Clear(Color.FromKnownColor(KnownColor.ButtonFace)); // 置背景色  
  157.             ShowBmp(); // 重繪全部區域  
  158.         }  
  159.  
  160.         #endregion  
  161.  
  162.         #region 動畫控制  
  163.  
  164.         /// <summary>  
  165.         /// 取消繪製。  
  166.         /// </summary>  
  167.         public void CancelDraw()  
  168.         {  
  169.             if (drawStarted)  
  170.             {  
  171.                 cancelEvent.Set();  
  172.             }  
  173.         }  
  174.  
  175.         /// <summary>  
  176.         /// 暫停繪製。  
  177.         /// </summary>  
  178.         public void PauseDraw()  
  179.         {  
  180.             if (drawStarted)  
  181.             {  
  182.                 pauseEvent.Set();  
  183.             }  
  184.         }  
  185.  
  186.         /// <summary>  
  187.         /// 繼續繪製。  
  188.         /// </summary>  
  189.         public void ResumeDraw()  
  190.         {  
  191.             if (drawStarted)  
  192.             {  
  193.                 pauseEvent.Reset();  
  194.             }  
  195.         }  
  196.  
  197.         #endregion  
  198.  
  199.         #region 構造函數  
  200.         /// <summary>  
  201.         /// 實例化後,需分配事件處理方法,全部事件均在獨立線程中觸發;默認延時係數爲1。  
  202.         /// </summary>  
  203.         /// <param name="inBmp">輸入位圖</param>  
  204.         public AnimatorImage(Bitmap inBmp)  
  205.         {  
  206.             delay = 1;  
  207.             this.bmp = (Bitmap)inBmp.Clone();  
  208.             outBmp = new Bitmap(this.bmp.Width, this.bmp.Height);  
  209.             dc = Graphics.FromImage(outBmp);  
  210.         }  
  211.  
  212.         #endregion  
  213.  
  214.         #region 繪製動畫  
  215.         /// <summary>  
  216.         /// 以獨立線程的方式開始顯示動畫。  
  217.         /// </summary>  
  218.         /// <param name="animateType">動畫類型枚舉</param>  
  219.         public void DrawAnimator(AnimateType animateType)  
  220.         {  
  221.             if (drawStarted) // 判斷動畫是否已經開始繪製  
  222.             {  
  223.                 if (pauseEvent.WaitOne(0)) // 動畫已開始,但被暫停了,繼續  
  224.                     pauseEvent.Reset();  
  225.                 else 
  226.                     pauseEvent.Set();  
  227.                 return;  
  228.             }  
  229.             ThreadStart threadMethod;  
  230.             switch (animateType)  
  231.             {  
  232.                 case AnimateType.Animator01:  
  233.                     threadMethod = Animator01;  
  234.                     break;  
  235.                 case AnimateType.Animator02:  
  236.                     threadMethod = Animator02;  
  237.                     break;  
  238.                 case AnimateType.Animator03:  
  239.                     threadMethod = Animator03;  
  240.                     break;  
  241.                 case AnimateType.Animator04:  
  242.                     threadMethod = Animator04;  
  243.                     break;  
  244.                 case AnimateType.Animator05:  
  245.                     threadMethod = Animator05;  
  246.                     break;  
  247.                 case AnimateType.Animator06:  
  248.                     threadMethod = Animator06;  
  249.                     break;  
  250.                 case AnimateType.Animator07:  
  251.                     threadMethod = Animator07;  
  252.                     break;  
  253.                 case AnimateType.Animator08:  
  254.                     threadMethod = Animator08;  
  255.                     break;  
  256.                 case AnimateType.Animator09:  
  257.                     threadMethod = Animator09;  
  258.                     break;  
  259.                 case AnimateType.Animator10:  
  260.                     threadMethod = Animator10;  
  261.                     break;  
  262.                 case AnimateType.Animator11:  
  263.                     threadMethod = Animator11;  
  264.                     break;  
  265.                 case AnimateType.Animator12:  
  266.                     threadMethod = Animator12;  
  267.                     break;  
  268.                 case AnimateType.Animator13:  
  269.                     threadMethod = Animator13;  
  270.                     break;  
  271.                 case AnimateType.Animator14:  
  272.                     threadMethod = Animator14;  
  273.                     break;  
  274.                 case AnimateType.Animator15:  
  275.                     threadMethod = Animator15;  
  276.                     break;  
  277.                 case AnimateType.Animator16:  
  278.                     threadMethod = Animator16;  
  279.                     break;  
  280.                 case AnimateType.Animator17:  
  281.                     threadMethod = Animator17;  
  282.                     break;  
  283.                 case AnimateType.Animator18:  
  284.                     threadMethod = Animator18;  
  285.                     break;  
  286.                 case AnimateType.Animator19:  
  287.                     threadMethod = Animator19;  
  288.                     break;  
  289.                 case AnimateType.Animator20:  
  290.                     threadMethod = Animator20;  
  291.                     break;  
  292.                 case AnimateType.Animator21:  
  293.                     threadMethod = Animator21;  
  294.                     break;  
  295.                 case AnimateType.Animator22:  
  296.                     threadMethod = Animator22;  
  297.                     break;  
  298.                 case AnimateType.Animator23:  
  299.                     threadMethod = Animator23;  
  300.                     break;  
  301.                 case AnimateType.Animator24:  
  302.                     threadMethod = Animator24;  
  303.                     break;  
  304.                 case AnimateType.Animator25:  
  305.                     threadMethod = Animator25;  
  306.                     break;  
  307.                 case AnimateType.Animator26:  
  308.                     threadMethod = Animator26;  
  309.                     break;  
  310.                 case AnimateType.Animator27:  
  311.                     threadMethod = Animator27;  
  312.                     break;  
  313.                 case AnimateType.Animator28:  
  314.                     threadMethod = Animator28;  
  315.                     break;  
  316.                 case AnimateType.Animator29:  
  317.                     threadMethod = Animator29;  
  318.                     break;  
  319.                 default:  
  320.                     threadMethod = Animator30;  
  321.                     break;  
  322.             }  
  323.             Thread drawThread = new Thread(threadMethod);  
  324.             drawThread.IsBackground = true// 設爲後臺線程,避免該線程未結束時退出主線程而引起異常  
  325.             drawThread.Start();  
  326.         }  
  327.  
  328.         #endregion  
  329.  
  330.         // ==========  
  331.         // 動畫算法  
  332.         // ==========  
  333.  
  334.         #region 壓縮反轉(改進版)  
  335.  
  336.         // 原理:計算圖像位置和高度,以高度的一半爲軸進行對換上下半邊的圖像  
  337.         private void Animator01()  
  338.         {  
  339.             const float blockSize = 8; // 每次顯示的高度增量,應能被高度整除  
  340.             try 
  341.             {  
  342.                 OnDrawStarted(this, EventArgs.Empty); // 觸發開始繪製事件  
  343.                 //ClearBackground();  
  344.  
  345.                 Color bgColor = Color.FromKnownColor(KnownColor.ButtonFace);  
  346.                 RectangleF srcRect = new RectangleF(0, 0, bmp.Width, bmp.Height);  
  347.                 for (float i = (float)Math.Floor(-bmp.Height / blockSize); i <= Math.Ceiling(bmp.Height / blockSize); i++)  
  348.                 {  
  349.                     dc.Clear(bgColor); // 清空DC  
  350.                     float j = i * blockSize / 2;  
  351.                     float destTop = bmp.Height / 2 - j; // 目標矩形的頂位置  
  352.                     // 目標矩形區域在循環的前半段爲垂直反向  
  353.                     RectangleF destRect = new RectangleF(0, destTop, bmp.Width, 2 * j);  
  354.                     // 在指定區域繪製圖像,該圖像被拉伸  
  355.                     dc.DrawImage(bmp, destRect, srcRect, GraphicsUnit.Pixel);  
  356.  
  357.                     ShowBmp();  
  358.                     Thread.Sleep(10 * delay); // 休眠  
  359.                 }  
  360.             }  
  361.             catch (Exception ex)  
  362.             {  
  363.                 ShowError(ex.Message);  
  364.             }  
  365.             finally 
  366.             {  
  367.                 OnDrawCompleted(this, EventArgs.Empty); // 觸發完成繪製事件  
  368.             }  
  369.         }  
  370.  
  371.         #endregion  
  372.  
  373.         #region 垂直對接(改進版)  
  374.  
  375.         // 原理:將圖像分爲上下部分,而後同時向中心移動  
  376.         private void Animator02()  
  377.         {  
  378.             const int stepCount = 4; // 每次上下移動的步長像素,應能被高度整除  
  379.             try 
  380.             {  
  381.                 OnDrawStarted(this, EventArgs.Empty);  
  382.                 ClearBackground();  
  383.  
  384.                 Rectangle sourTopRect = new Rectangle(0, 0, bmp.Width, bmp.Height / 2); // 上半部分源區域  
  385.                 Rectangle sourBottRect = new Rectangle(0, bmp.Height / 2, bmp.Width, bmp.Height / 2); // 下半部分源區域  
  386.                 for (int i = 0; i <= bmp.Height / 2; i += stepCount)  
  387.                 {  
  388.                     Rectangle destTopRect = new Rectangle(0, i - bmp.Height / 2 + 1, bmp.Width, bmp.Height / 2); // 上半部分目標區域  
  389.                     Rectangle destBottRect = new Rectangle(0, bmp.Height - i - 1, bmp.Width, bmp.Height / 2); // 下半部分目標區域  
  390.                     dc.DrawImage(bmp, destTopRect, sourTopRect, GraphicsUnit.Pixel);  
  391.                     dc.DrawImage(bmp, destBottRect, sourBottRect, GraphicsUnit.Pixel);  
  392.  
  393.                     ShowBmp(Rectangle.Union(destTopRect, destBottRect));  
  394.                     Thread.Sleep(10 * delay);  
  395.                 }  
  396.             }  
  397.             catch (Exception ex)  
  398.             {  
  399.                 ShowError(ex.Message);  
  400.             }  
  401.             finally 
  402.             {  
  403.                 OnDrawCompleted(this, EventArgs.Empty);  
  404.             }  
  405.         }  
  406.  
  407.         #endregion  
  408.  
  409.         #region 中心閉幕(改進版)  
  410.  
  411.         // 原理:由大到小生成圖像中心區域,而後用總區域減去該中心區域,並用材質畫刷填充  
  412.         private void Animator03()  
  413.         {  
  414.             const float stepCount = 4; // 每次收縮的步長像素  
  415.             try 
  416.             {  
  417.                 OnDrawStarted(this, EventArgs.Empty);  
  418.                 ClearBackground();  
  419.  
  420.                 // 創建空區域,如使用Region的無參構造函數則創建一個無限大小的區域,而非空區域  
  421.                 Region region = new Region(new GraphicsPath());  
  422.                 // 創建位圖材質畫刷  
  423.                 TextureBrush textureBrush = new TextureBrush(bmp);  
  424.                 for (float x = 0; x <= bmp.Width / 2f; x += stepCount)  
  425.                 {  
  426.                     // 添加整個位圖區域  
  427.                     region.Union(new Rectangle(0, 0, bmp.Width, bmp.Height));  
  428.                     // 從中心開始,由大到小填充背景色或填充縮小尺寸的原圖  
  429.                     // 計算高度變化量,若是寬度大,則高度變化量小於寬度,不然大於寬度  
  430.                     float y = x * bmp.Height / bmp.Width;  
  431.                     RectangleF rect = new RectangleF(x, y, bmp.Width - 2f * x, bmp.Height - 2f * y);  
  432.                     // 計算整個位圖區域與背景色區域的差集  
  433.                     region.Exclude(rect);  
  434.                     dc.FillRegion(textureBrush, region); // 使用材質畫刷填充區域  
  435.  
  436.                     ShowBmp(region.GetBounds(dc));  
  437.                     Thread.Sleep(10 * delay);  
  438.                 }  
  439.                 // 因爲stepCount可能沒法被寬度整除,則最終生成的背景色區域並不爲空,故在循環結束後繪製整個位圖  
  440.                 dc.DrawImage(bmp, 0, 0);  
  441.  
  442.                 ShowBmp();  
  443.             }  
  444.             catch (Exception ex)  
  445.             {  
  446.                 ShowError(ex.Message);  
  447.             }  
  448.             finally 
  449.             {  
  450.                 OnDrawCompleted(this, EventArgs.Empty);  
  451.             }  
  452.         }  
  453.  
  454.         #endregion  
  455.  
  456.         #region 中心放大(改進版)  
  457.  
  458.         // 原理:由中心向邊緣按高度和寬度的比例循環輸出全部像素,直到高度和寬度爲原始大小  
  459.         private void Animator04()  
  460.         {  
  461.             const int stepCount = 4; // 每次增長的像素量,應能被寬度整除  
  462.             try 
  463.             {  
  464.                 OnDrawStarted(this, EventArgs.Empty);  
  465.                 ClearBackground();  
  466.  
  467.                 Rectangle sourRect = new Rectangle(0, 0, bmp.Width, bmp.Height); // 源區域爲整個位圖  
  468.                 for (int i = 0; i <= bmp.Width / 2; i += stepCount)  
  469.                 {  
  470.                     int j = i * bmp.Height / bmp.Width; // 計算高度變化量,若是寬度大,則高度變化量小於寬度,不然大於寬度  
  471.                     Rectangle destRect = new Rectangle(bmp.Width / 2 - i, bmp.Height / 2 - j, 2 * i, 2 * j);  
  472.                     dc.DrawImage(bmp, destRect, sourRect, GraphicsUnit.Pixel);  
  473.  
  474.                     ShowBmp(destRect);  
  475.                     Thread.Sleep(10 * delay);  
  476.                 }  
  477.             }  
  478.             catch (Exception ex)  
  479.             {  
  480.                 ShowError(ex.Message);  
  481.             }  
  482.             finally 
  483.             {  
  484.                 OnDrawCompleted(this, EventArgs.Empty);  
  485.             }  
  486.         }  
  487.  
  488.         #endregion  
  489.  
  490.         #region 逐行分塊  
  491.  
  492.         // 原理:將圖像分爲正方形塊,而後從左到右,從上到下順序顯示  
  493.         private void Animator05()  
  494.         {  
  495.             const float blockSize = 50; // 正方塊的邊長  
  496.             try 
  497.             {  
  498.                 OnDrawStarted(this, EventArgs.Empty);  
  499.                 ClearBackground();  
  500.  
  501.                 // 防止最後一列、最後一行不足一塊的尺寸而不顯示,故採用上取整  
  502.                 for (int y = 0; y < Math.Ceiling(bmp.Height / blockSize); y++)  
  503.                 {  
  504.                     for (int x = 0; x < Math.Ceiling(bmp.Width / blockSize); x++)  
  505.                     {  
  506.                         RectangleF rect;  
  507.                         if (y % 2 == 0) // 從左到右  
  508.                         {  
  509.                             rect = new RectangleF(x * blockSize, y * blockSize, blockSize, blockSize);  
  510.                         }  
  511.                         else // 從右到左  
  512.                         {  
  513.                             rect = new RectangleF((bmp.Width / blockSize - x - 1) * blockSize, y * blockSize, blockSize, blockSize);  
  514.                         }  
  515.                         dc.DrawImage(bmp, rect, rect, GraphicsUnit.Pixel);  
  516.  
  517.                         ShowBmp(rect);  
  518.                         Thread.Sleep(10 * delay);  
  519.                     }  
  520.                 }  
  521.             }  
  522.             catch (Exception ex)  
  523.             {  
  524.                 ShowError(ex.Message);  
  525.             }  
  526.             finally 
  527.             {  
  528.                 OnDrawCompleted(this, EventArgs.Empty);  
  529.             }  
  530.         }  
  531.  
  532.         #endregion  
  533.  
  534.         #region 交替分塊(改進版)  
  535.  
  536.         // 原理:將圖像分爲正方形塊,而後計算全部分塊按照奇偶從左到右顯示或從右到左顯示所需的區域,並用材質畫刷填充  
  537.         private void Animator06()  
  538.         {  
  539.             const float blockSize = 70; // 正方塊的邊長  
  540.             const int showWidth = 1; // 每次顯示的像素列數  
  541.             try 
  542.             {  
  543.                 OnDrawStarted(this, EventArgs.Empty);  
  544.                 ClearBackground();  
  545.  
  546.                 // 創建空區域,如使用Region的無參構造函數則創建一個無限大小的區域,而非空區域  
  547.                 Region region = new Region(new GraphicsPath());  
  548.                 // 創建位圖材質畫刷  
  549.                 TextureBrush textureBrush = new TextureBrush(bmp);  
  550.                 // 分塊的行座標+列座標爲偶數則從左到右逐列顯示本塊,不然從右到左逐列顯示本塊  
  551.                 for (int i = 0; i <= Math.Ceiling(blockSize / showWidth); i++)  
  552.                 {  
  553.                     for (int x = 0; x < Math.Ceiling(bmp.Width / blockSize); x++)  
  554.                     {  
  555.                         for (int y = 0; y < Math.Ceiling(bmp.Height / blockSize); y++)  
  556.                         {  
  557.                             RectangleF rect;  
  558.                             // 判斷塊的行列座標和爲奇數或偶數  
  559.                             if ((x + y) % 2 == 0)  
  560.                             {  
  561.                                 rect = new RectangleF(x * blockSize + i * showWidth, y * blockSize, showWidth, blockSize);  
  562.                             }  
  563.                             else 
  564.                             {  
  565.                                 rect = new RectangleF((x + 1) * blockSize - i * showWidth, y * blockSize, showWidth, blockSize);  
  566.                             }  
  567.                             region.Union(rect); // 將要顯示的區域合併到region中  
  568.                         }  
  569.                     }  
  570.                     dc.FillRegion(textureBrush, region); // 使用材質畫刷填充區域  
  571.  
  572.                     ShowBmp(region.GetBounds(dc));  
  573.                     Thread.Sleep(10 * delay);  
  574.                 }  
  575.             }  
  576.             catch (Exception ex)  
  577.             {  
  578.                 ShowError(ex.Message);  
  579.             }  
  580.             finally 
  581.             {  
  582.                 OnDrawCompleted(this, EventArgs.Empty);  
  583.             }  
  584.         }  
  585.  
  586.         #endregion  
  587.  
  588.         #region 交叉豎條(改進版)  
  589.  
  590.         // 原理:將圖像分紅寬度相等的列,而後計算從上下兩個方向交叉前進的區域,並使用材質畫刷填充  
  591.         private void Animator07()  
  592.         {  
  593.             const float lineWidth = 4; // 豎條寬度  
  594.             const float lineStep = 6; // 豎條每次前進的步長  
  595.             try 
  596.             {  
  597.                 OnDrawStarted(this, EventArgs.Empty);  
  598.                 ClearBackground();  
  599.  
  600.                 GraphicsPath path = new GraphicsPath(); // 創建路徑,路徑處理速度要明顯快於Region,但不支持集合運算  
  601.                 TextureBrush textureBrush = new TextureBrush(bmp);  
  602.                 // 從上到下和從下到上以步長爲單位顯示  
  603.                 for (int y = 0; y < Math.Ceiling(bmp.Height / lineStep); y++)  
  604.                 {  
  605.                     // 顯示兩個方向的每一個垂直豎條  
  606.                     for (int x = 0; x < Math.Ceiling(bmp.Width / lineWidth); x++)  
  607.                     {  
  608.                         RectangleF rect;  
  609.                         if (x % 2 == 0) // 從上到下  
  610.                         {  
  611.                             rect = new RectangleF(x * lineWidth, y * lineStep, lineWidth, lineStep);  
  612.                         }  
  613.                         else // 從下到上  
  614.                         {  
  615.                             rect = new RectangleF(x * lineWidth, bmp.Height - y * lineStep - lineStep, lineWidth, lineStep);  
  616.                         }  
  617.                         path.AddRectangle(rect);  
  618.                     }  
  619.                     dc.FillPath(textureBrush, path);  
  620.  
  621.                     ShowBmp(path.GetBounds());  
  622.                     Thread.Sleep(10 * delay);  
  623.                 }  
  624.             }  
  625.             catch (Exception ex)  
  626.             {  
  627.                 ShowError(ex.Message);  
  628.             }  
  629.             finally 
  630.             {  
  631.                 OnDrawCompleted(this, EventArgs.Empty);  
  632.             }  
  633.         }  
  634.  
  635.         #endregion  
  636.  
  637.         #region 透明淡入(改進版)  
  638.  
  639.         // 原理:使用ImageAttributes類和顏色轉換矩陣處理圖像,使每一個像素的顏色份量同步增長  
  640.         private void Animator08()  
  641.         {  
  642.             const float stepCount = 0.02f; // 顏色轉換矩陣增量,該值除1應等於整數  
  643.             try 
  644.             {  
  645.                 OnDrawStarted(this, EventArgs.Empty);  
  646.                 ClearBackground();  
  647.  
  648.                 // ImageAttributes類的實例用於調整顏色,由DrawImage()方法調用  
  649.                 ImageAttributes attributes = new ImageAttributes();  
  650.                 // 創建5*5階RGBA顏色矩陣  
  651.                 ColorMatrix matrix = new ColorMatrix();  
  652.                 float value = 0;  
  653.                 while (value < 1f)  
  654.                 {  
  655.                     matrix.Matrix33 = value;  
  656.                     // 爲ImageAttributes對象指定顏色調整矩陣  
  657.                     // ColorMatrixFlag.Default表示使用矩陣調整全部顏色;ColorAdjustType.Bitmap表示調整位圖的顏色  
  658.                     attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);  
  659.                     dc.Clear(Color.FromKnownColor(KnownColor.ButtonFace)); // 清空DC,不然每次會將不一樣的透明度圖像疊加顯示  
  660.                     dc.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);  
  661.                     value += stepCount;  
  662.  
  663.                     ShowBmp();  
  664.                     Thread.Sleep(10 * delay);  
  665.                 }  
  666.             }  
  667.             catch (Exception ex)  
  668.             {  
  669.                 ShowError(ex.Message);  
  670.             }  
  671.             finally 
  672.             {  
  673.                 OnDrawCompleted(this, EventArgs.Empty);  
  674.             }  
  675.         }  
  676.  
  677.         #endregion  
  678.  
  679.         #region 三色淡入  
  680.  
  681.         // 原理:使用ImageAttributes類和顏色轉換矩陣處理圖像,分三次增長每一個像素的單個顏色份量  
  682.         private void Animator09()  
  683.         {  
  684.             const float stepCount = 0.025f; // 顏色轉換矩陣增量,該值除1應等於整數  
  685.             try 
  686.             {  
  687.                 OnDrawStarted(this, EventArgs.Empty);  
  688.                 ClearBackground();  
  689.  
  690.                 // ImageAttributes類的實例用於調整顏色,由DrawImage()方法調用  
  691.                 ImageAttributes attributes = new ImageAttributes();  
  692.                 // 創建5*5階RGBA顏色矩陣  
  693.                 ColorMatrix matrix = new ColorMatrix();  
  694.                 matrix.Matrix00 = 0f; // R爲0  
  695.                 matrix.Matrix11 = 0f; // G爲0  
  696.                 matrix.Matrix22 = 0f; // B爲0  
  697.                 // 如下三個循環依次處理B、R、G,符合亮度方程的原理  
  698.                 // 人眼對B最不敏感,對G最敏感,或者說B傳達的亮度信息最少,G傳達的亮度信息最多  
  699.                 // 所以先處理亮度信息少的,最後處理亮度信息多的,若是反過來處理,則變化不明顯  
  700.                 float value = 0f;  
  701.                 while (value < 1f)  
  702.                 {  
  703.                     matrix.Matrix22 = value; // 顏色R的轉換矩陣份量值  
  704.                     // 爲ImageAttributes對象指定顏色調整矩陣  
  705.                     // ColorMatrixFlag.Default表示使用矩陣調整全部顏色;ColorAdjustType.Bitmap表示調整位圖的顏色  
  706.                     attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);  
  707.                     dc.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);  
  708.                     value += stepCount;  
  709.  
  710.                     ShowBmp();  
  711.                     Thread.Sleep(10 * delay);  
  712.                 }  
  713.                 value = stepCount;  
  714.                 while (value < 1f)  
  715.                 {  
  716.                     matrix.Matrix00 = value; // 顏色G的轉換矩陣份量值  
  717.                     attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);  
  718.                     dc.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);  
  719.                     value += stepCount;  
  720.  
  721.                     ShowBmp();  
  722.                     Thread.Sleep(10 * delay);  
  723.                 }  
  724.                 value = stepCount;  
  725.                 while (value < 1f)  
  726.                 {  
  727.                     matrix.Matrix11 = value; // 顏色B的轉換矩陣份量值  
  728.                     attributes.SetColorMatrix(matrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);  
  729.                     dc.DrawImage(bmp, new Rectangle(0, 0, bmp.Width, bmp.Height), 0, 0, bmp.Width, bmp.Height, GraphicsUnit.Pixel, attributes);  
  730.                     value += stepCount;  
  731.  
  732.                     ShowBmp();  
  733.                     Thread.Sleep(10 * delay);  
  734.                 }  
  735.             }  
  736.             catch (Exception ex)  
  737.             {  
  738.                 ShowError(ex.Message);  
  739.             }  
  740.             finally 
  741.             {  
  742.                 OnDrawCompleted(this, EventArgs.Empty);  
  743.             }  
  744.         }  
  745.  
  746.         #endregion  
  747.  
  748.         #region 水平拉幕  
  749.  
  750.         // 原理:由中心向開始逐漸輸出中心兩側的像素,直到寬度爲原始大小  
  751.         private void Animator10()  
  752.         {  
  753.             const int stepCount = 4; // 每次增長的步長像素,該值應能被寬度整除  
  754.             try 
  755.             {  
  756.                 OnDrawStarted(this, EventArgs.Empty);  
  757.                 ClearBackground();  
  758.  
  759.                 for (int i = 0; i <= Math.Ceiling(bmp.Width / 2f); i += stepCount)  
  760.                 {  
  761.                     Rectangle rect = new Rectangle(bmp.Width / 2 - i, 0, 2 * i, bmp.Height);  
  762.                     dc.DrawImage(bmp, rect, rect, GraphicsUnit.Pixel);  
  763.  
  764.                     ShowBmp(rect);  
  765.                     Thread.Sleep(10 * delay);  
  766.                 }  
  767.             }  
  768.             catch (Exception ex)  
  769.             {  
  770.                 ShowError(ex.Message);  
  771.             }  
  772.             finally 
  773.             {  
  774.                 OnDrawCompleted(this, EventArgs.Empty);  
  775.             }  
  776.         }  
  777.  
  778.         #endregion 

    本文的最後一部分(下),會附上完整的項目文件組,包含全部資源及可執行文件。
這裏是本文的第二部分:http://mengliao.blog.51cto.com/876134/473193算法

相關文章
相關標籤/搜索