利用GDI+绘制验证码

.Net中封装了一个GDI+绘图画面在Graphics类中,该类是个密封类,不能被继承。我们可以利用该类中的各种方法来进行绘图,现在来用GDI+绘制验证码.

      正如这张图片所示:

我们要的是:1、五个随机的数字;2、每个数字字体类型随机;3、每个数字的字体大小随机;4、每个数字的字体颜色随机;5、每个数字的字体坐标局部随机(为了避免数字重叠,每个数字的活动范围都要限制)。上面五个要求我们很容易想到怎样去实现,现在要做的就是怎样将数字绘制上去。我们一步一步来,我先来说明怎样去使用GDI+。

      绘图最简单的就是绘制直线了,想想我们现实生活中要画一条线需要什么?1、一个人(来做这件事)2、一支笔(工具)3、一张纸(承载要绘制的线条),4、要绘制的直线的两个端点的坐标(两点确定一条直线)。同样的在这里也是,我们需要一个做这件事的“人”,也就是GDI+对象了。面向对象就是这样,需要做一件事情就去找能做这件事情的对象。还需要一支画笔,就是Pen对象。剩下的就是纸了,在.Net里,GDI+是封装在Graphics类中的,该类不能通过new来创建实例,必须通过其他对象类创建,这样就使谁创建了该GDI+对象,该GDI+对象就把谁当做画布,这就是我们绘图需要的纸了。下面这段代码是在Form窗体上绘制一条直线:

/// <summary>
        /// 绘制一条直线
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnDraw_Click(object sender, EventArgs e)
        {
            //用当前窗体对象来创建一个GDI+对象,此时当前窗体被当做画布
            Graphics gp = this.CreateGraphics();
            //创建一只画笔,并且设置画笔颜色
		//在这里我们也可用刷子的颜色Pen pen = new Pen(Brushes.Red);
       //Brushes与Color的区别就是Brushes可以用来填充图形,而如果用Color的话不能用来填充
            Pen myPen = new Pen(Color.Red);
            //创建两个Point对象,表示直线的两个端点
            Point pointOne = new Point(100, 100);
            Point pointTwo = new Point(200, 200);
            //调用GDI+对象的绘制直线方法绘制直线
            gp.DrawLine(myPen, pointOne, pointTwo);

        }

在这里要说一个问题,绘制出这条直线后我们把窗体拖动值边缘让边缘遮挡我们绘制的直线然后再将窗体拖出来,你会发现我们绘制的直线被擦掉了一部分。这个跟窗体重绘有关,具体的我也不了解,等我了解了再贴上来。

下面我们就利用GDI+来绘制验证码图片:

   验证码是一张图片,图片要放在pictureBox中,我们做好这样一个界面:

我们要将验证码绘制在位图(Bitmap)中,然后将该位图放入pictureBox中。所以该位图就是我们的画布,创建一个位图对象并设置其长度跟宽度:

Bitmap myBmp = new Bitmap(150, 30);

再用myBmp创建GDI+对象:

Graphics myGp = Graphics.FromImage(myBmp);

接下来应该创建Pen对象的,但由于创建画笔对象时必须提供画笔颜色,这样对于我们随机绘制不同颜色的数字来说就不符合要求。所以我们选择在需要画笔的时候再创建画笔对象。

现在让我们来创建一个产生随机数的对象:

Random r = new Random();

利用Random对象产生五个随机数作为验证码数字并将这五个验证码合成一个字符串:

string pass = null;
            for (int i = 0; i < 5; i++)
            {
                pass += r.Next(0, 10);
            }

得到了五个随机数后我们需要随机给这五个数字不同的字体及颜色 , 所以我们把字体类型及颜色类型都存到数组中 , 再利用随机数作为数组下标来调用 :

//声明一个字符串数组,用来存储字体类型
            string[] font = { "微软雅黑", "仿宋", "幼圆", "宋体", "隶书" };
            //声明一个Color数组,用来储存字体颜色
            Color[] colors = { Color.Red, Color.Yellow, Color.Blue, Color.Black, Color.Pink };

接下来要做的就是将验证码数字绘制出来,在绘制数字时调用DrawString()方法来绘制对应数字,其中四个参数分别为1、要绘制的数字2、数字的字体3、字体的颜色4、字体的坐标点(字体左上角的坐标)。对于字体的坐标,由于五个数字要避免重合,我们让他们X轴间距固定,代码如下:

Point point=new Point ();
            for (int i = 0; i < 5; i++)
            {
                point.X=30*i;
                point.Y=r.Next(0,15);
                //调用GDI+的DrawString方法来绘制字符串
                myGp.DrawString(pass[i].ToString(), new Font(font[r.Next(0, 5)], 20, FontStyle.Italic), new SolidBrush(colors[r.Next(0, 5)]), point);
            }

最主要的绘制数字完成了,现在我们要绘制一些线条来让验证码看起来模糊一些,直接贴代码了:

//绘制线条
            //声明两个直线的端点
            Point pointA = new Point();
            Point pointB = new Point();
            for (int i = 0; i < 15; i++)
            {
                //随机给点赋坐标
                pointA.X = r.Next(0, myBmp.Width);
                pointA.Y = r.Next(0, myBmp.Height);
                pointB.X = r.Next(0, myBmp.Width);
                pointB.Y = r.Next(0, myBmp.Height);
                //绘制线条
                myGp.DrawLine(new Pen(colors[r.Next(0, 5)]), pointA, pointB);
            }

绘制完了线条,再给验证码图片增加一点噪点,增加噪点不需要用到GDI+绘制,直接利用位图中的SetPixel()方法设置指定坐标像素的颜色来设置噪点:

//绘制噪点
            Point pointC = new Point();
            for (int i = 0; i < 300; i++)
            {
                pointC.X = r.Next(0, myBmp.Width);
                pointC.Y = r.Next(0, myBmp.Height);
                //噪点直接用位图对象直接绘制
                myBmp.SetPixel(pointC.X, pointC.Y, colors[r.Next(0, 5)]);
            }

现在噪点也设置好了,最后一步就是将位图放到pictureBox中了:

//将绘制好的位图放到pictrueBox中
            pictureBox1.Image = myBmp;

现在将完整代码贴出来:

/// <summary>
        /// 更换验证码图片
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void btnChange_Click(object sender, EventArgs e)
        {
            //创建一个位图对象,并设置该位图的长宽
            Bitmap myBmp = new Bitmap(150, 50);
            //用myBmp创建一个GDI+对象
            Graphics myGp = Graphics.FromImage(myBmp);
            //创建一个产生随机数的对象
            Random r = new Random();
            //生成五个随机数作为验证码数字
            //将五个随机数合成一个字符串
            string pass = null;
            for (int i = 0; i < 5; i++)
            {
                pass += r.Next(0, 10);
            }
            //声明一个字符串数组,用来存储字体类型
            string[] font = { "微软雅黑", "仿宋", "幼圆", "宋体", "隶书" };
            //声明一个Color数组,用来储存字体颜色
            Color[] colors = { Color.Red, Color.Yellow, Color.Blue, Color.Black, Color.Pink };
            //绘制验证码
            //验证码字体类型、颜色,字体的坐标都是随机的
            //能声明在循环外面的变量尽量声明在循环外面
            Point point=new Point ();
            for (int i = 0; i < 5; i++)
            {
                point.X=30*i;
                point.Y=r.Next(0,15);
                //调用GDI+的DrawString方法来绘制字符串
                myGp.DrawString(pass[i].ToString(), new Font(font[r.Next(0, 5)], 20, FontStyle.Italic), new SolidBrush(colors[r.Next(0, 5)]), point);
            }
            //绘制线条
            //声明两个直线的端点
            Point pointA = new Point();
            Point pointB = new Point();
            for (int i = 0; i < 15; i++)
            {
                //随机给点赋坐标
                pointA.X = r.Next(0, myBmp.Width);
                pointA.Y = r.Next(0, myBmp.Height);
                pointB.X = r.Next(0, myBmp.Width);
                pointB.Y = r.Next(0, myBmp.Height);
                //绘制线条
                myGp.DrawLine(new Pen(colors[r.Next(0, 5)]), pointA, pointB);
            }
            //绘制噪点
            Point pointC = new Point();
            for (int i = 0; i < 300; i++)
            {
                pointC.X = r.Next(0, myBmp.Width);
                pointC.Y = r.Next(0, myBmp.Height);
                //噪点直接用位图对象直接绘制
                myBmp.SetPixel(pointC.X, pointC.Y, colors[r.Next(0, 5)]);
            }
            //将绘制好的位图放到pictrueBox中
            pictureBox1.Image = myBmp;

        }



  • 1
    点赞
  • 0
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:大白 设计师:CSDN官方博客 返回首页
评论

打赏作者

磊大不小

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值