扭曲的验证码

  当初学习一般处理程序的时候,写过一个验证码,不过是后台程序向前台输出了一张图片,图片上是几个随机写上去的字符。虽然也惊讶于许多网站上那些“扭曲”的验证码,却琢磨不透人家是怎么实现的,后来逐渐把这事遗忘了。今天在网上碰巧看到有人用php实现的案例,忍不住想着用C#来一把。当然,在此先感谢网上那位仁兄提供的思路,在下只是比着葫芦画瓢。

  这里所说的“扭曲”的验证码,只是字符扭曲。由于时间仓促,我也没给顾得上添加图片噪点。先说思路:创建图片A做为背景,其次创建图片B,在图片B画上验证码文字,然后将图片B拆分成若干部分画到图片A上。打个比方,好比是把一张画纵向平均裁成若干份,然后再上下交错着粘到另一张白纸上。如果随意的上下交错排列,看到的八成就是一片乱七八糟的玩意儿,这里不妨按照一个曲线变化的规律来排列,我选择的是正弦曲线。

  步骤:

  1、新建一般处理程序TestCodeHandler.ashx,先定义一个随机生成验证码文字的方法,如下:

        /// <summary>
        /// 随机生成验证码
        /// </summary>
        /// <returns></returns>
        public string GetTestCode()
        {
            Random r = new Random();

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < 5; i++)
            {
                int n = r.Next(65, 91);
                sb.Append((char)n);
            }
            return sb.ToString();
        }    

  2、在ProcessRequest方法中,确定输出文件的类型。  

 context.Response.ContentType = "image/jpeg";

  3、引用命名空间System.Drawing和using System.Drawing.Imaging生成验证码图片。

            using (Image img = new Bitmap(85, 40))//背景图片
            {
                using (Image fontImg = new Bitmap(84, 38))//预先画验证码的临时图片
                {
                    //先将验证码画到临时图片fontImg上
                    using (Graphics fontGraphic = Graphics.FromImage(fontImg))
                    {
                        fontGraphic.Clear(Color.White);//将画布涂白
                        //画验证吗
                        fontGraphic.DrawString(GetTestCode(), new Font("宋体", 18, FontStyle.Italic | FontStyle.Bold), Brushes.Black, new PointF(4, 4));
                    }
                    //将临时验证码图片fontImg分成若干份画到背景图片img上
                    using (Graphics g = Graphics.FromImage(img))
                    {
                        g.Clear(Color.White);//将画布涂白                       
                        int sum = 60;//分成60份
                        int niu = 6;//上下最多偏移10像素
                        float x = 0, y = 1;//从临时图片fontImg选取矩形区域的起始坐标
                        //从临时图片fontImg选取矩形区域的宽度,由于有背景图片映衬,这里只确定宽度                        
                        float width = ((float)fontImg.Width) / sum;
                        //依次把临时图片fontImg各部分画到背景图片上                       
                        for (int i = 0; i < sum; i++)
                        {                            
                            //获取当前部分的正弦值,计算上下偏移量。但这样会使验证码的扭曲单一
                            float rate = (float)Math.Sin(360 * 1.0 / sum * i / 180 * Math.PI) * niu;
                            //如果使用随机数,会有不同的变化
                            //Random r = new Random(DateTime.Now.Millisecond);
                            //float rate = (float)Math.Sin(360 * 1.0 / sum * i / 180 * Math.PI) * r.Next(1,niu);

                            //把临时图片fontImg当前部分画到背景图片上
                            g.DrawImage(fontImg, new Rectangle(x==0?1:(int)x, (int)y, img.Width, img.Height - 2), x, y * rate, width, fontImg.Height, GraphicsUnit.Pixel);
                            //依次改变横坐标的下一个位置
                            x += width;                           
                            
                        }
                        //为背景图片画边框
                        g.DrawRectangle(new Pen(Brushes.Black), new Rectangle(0, 0, img.Width - 1, img.Height - 1));
                    }
                }
                //将背景图片保存到输出流
                img.Save(context.Response.OutputStream, ImageFormat.Jpeg);

  4、测试。新建html页面,添加<img>标签,令src属性指向TestCodeHandler.ashx,并为它的onclick事件注册方法,实现点击切换图片的效果。如下:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
    <script type="text/javascript">
        function change() {
            document.getElementById("img").src = "TestCodeHandler.ashx?id=" + new Date().getTime();
        }
    </script>
</head>
<body>
    <img id="img" src="TestCodeHandler.ashx"  onclick="change()"/>
</body>
</html>

  5、效果如下: 

     

  恕在下能力一般,水平有限,也只能实现上面的效果。若有高人看到此文,发现有不到之处,还望不吝赐教。

  

原文地址:https://www.cnblogs.com/wcfl/p/3795478.html