C#自定義畫刷原理解析

windows系統中的畫板工具,有好幾種畫刷,C#中並沒有直接對應可使用的類,隻能自己研究。

1.畫刷原理

根據本人對PS的相關功能細心分析,發現各種畫刷其實就是一幅圖片的移位重疊顯示。通常這幅畫刷圖是半透明的,隻有其中一些區域有顏色。

上圖中的畫刷,把間隔設大之後可以明顯看到原圖的模樣。

這是基於位移的畫刷,另外有基於時間的,比如噴槍工具。

2.代碼實現

1).  直線算法

為什麼要直線算法?因為我們移動鼠標,觸發MouseMove事件,記錄鼠標前一坐標點與當前點,如果兩點是是相鄰的,當然不需要再做多餘的算法,當如果兩點是不相鄰的,我們就需要計算兩點之間所有的點。否則無法有效地進行固定間隔繪制畫刷圖。

/// <summary>
/// 順序獲取兩點間直線上的所有點
/// </summary>
/// <param name="pStart">開始點</param>
/// <param name="pEnd">結束點</param>
/// <returns>兩點間直線上的所有點</returns>
private List<Point> getPoint2Point(Point pStart, Point pEnd)
        {
            List<Point> linePoint = new List<Point>();
            if (pStart.X == pEnd.X && pStart.Y == pEnd.Y)
            {
                linePoint.Add(pStart);
                return linePoint;
            }
            DDALine(pStart.X, pStart.Y, pEnd.X, pEnd.Y, ref  linePoint);
            return linePoint;
        }
        //DDA直線畫法
        private void DDALine(int x0, int y0, int x1, int y1, ref List<Point> ptl) 
        {  
            int dx,dy,eps1,k;  
            float x,y,xIncre,yIncre;  
            dx=x1-x0;  
            dy=y1-y0;  
            x=x0;  
            y=y0;  
            if(Math.Abs(dx)>Math.Abs(dy))  
            eps1=Math.Abs(dx);  
            else  
            eps1=Math.Abs(dy);  
            xIncre=(float)dx/(float)eps1;  
            yIncre=(float)dy/(float)eps1;  
            for(k=0;k<=eps1;k++)  
            {
                ptl.Add( new Point((int)(x + 0.5), (int)(y + 0.5)) );  
                x+=xIncre;  
                y+=yIncre;  
            }  
        } 

2).鼠標事件

分別為鼠標按下、移動、放開事件

bool bIsDraw = false; //主圖畫線
Point startPoint_Draw = new Point();//劃線點變量
List<Point> pts = new List<Point>();//畫點保存
private void pictureBox_main_MouseMove(object sender, MouseEventArgs e)
 {
            PictureBox pb = sender as PictureBox;
            ssl_point.Text = e.Location.ToString();
            pb.Refresh();
            if (bIsDraw)
            {
                Point p = limitPoint(e.Location, pictureBox_main.ClientSize);
                if (p == startPoint_Draw) return;
                Graphics gs = Graphics.FromImage(pb.Image);
                if (pictureBox_main.Image != null  )
                {
                     List<Point> pl =  getPoint2Point(startPoint_Draw,  p);
                     pl.RemoveAt(0);
                     pts.AddRange(pl);
                     if (pts.Count >= peninv)
                     {
                         for (int i = penmod; i < pts.Count; i += peninv)
                         {
                             gs.DrawImage(blushbmp_curr, pts[i].X - pensize , pts[i].Y - pensize  , pensize*2, pensize*2);
                         }
                         penmod = pts.Count % peninv;
                         pts.RemoveRange(0, pts.Count - penmod);
                     } 
                }
                gs.Dispose();
                startPoint_Draw = p;
            }
        }
        private void pictureBox_main_MouseDown(object sender, MouseEventArgs e)
        {
            if(e.Button == System.Windows.Forms.MouseButtons.Left)
            if (bIsDraw == false)
            {
                startPoint_Draw = e.Location;
                pts.Clear();
                pts.Add(startPoint_Draw);
                bIsDraw = true;
            }
        }
        private void pictureBox_main_MouseUp(object sender, MouseEventArgs e)
        {
            if (bIsDraw == true)
            {
                bIsDraw = false;
                if (pictureBox_main.Image != null   )
                {
                     pts.Clear();
                }
                pictureBox_main.Refresh();   
            }
        }

如果根據位移方向加上圖片的角度旋轉效果,應該會更加接近PS的效果。

3.效果

我使用的畫刷圖就是來源於本文上圖的PS畫刷。

圖中5條畫刷線分別使用間隔1,10,20,40,80。使用不同的原圖,就能得到各種各樣的畫刷。

以上就是本文的全部內容,希望對大傢的學習有所幫助,也希望大傢多多支持WalkonNet。

推薦閱讀: