默之's profile个人随笔PhotosBlogListsMore Tools Help

Blog


    March 16

    .NET学习,生成图片验证码(二)

        上一篇,我已经实现了简单的图片验证码。但是该图片验证码看上去比较简单没有什么特效,不像其他网站上的验证码具有扭曲,和图片背景有噪音点的功能,这次我就准备实现这个功能。
        一、图片背景噪音点的实现
        实现思路:就是在内存图片上通过setPixel方法,设置指定像素点的颜色。
        //字符串数组,存放颜色
        private static string[] BrushName = new string[]{"OliveDrab","ForestGreen", "DarkCyan", "LightSlateGray", "RoyalBlue",  
    "SlateBlue", "DarkViolet","MediumVioletRed","IndianRed","Firebrick",
    "Chocolate", "Peru","Goldenrod",  "Teal",  "DarkGreen",
    "MediumBlue",  "Black" };
            /// <summary>
            /// 绘制图片噪音点
            /// </summary>
            /// <param name="image">图片对象</param>
            public void stainImage(Bitmap image)
            {
                Random rnd = new Random();
                //随机选择颜色
                int index = rnd.Next(BrushName.Length);
                //在图形上画20个点数字可以进行修改
                for (int n = 0; n < 20; n++)
                {
                    int x = rnd.Next(image.Width-2);
                    int y = rnd.Next(image.Height-2);
                    image.SetPixel(x, y, Color.FromName(BrushName[index]));
                }
            }
          
            二、扭曲图片实现
            实现思路:按列循环整张图片,获取每个像素点的颜色,并通过正弦曲线获取另一个像素点的位置,用原始像素点的颜色替换正弦像素点的颜色,就可以得到一张扭曲的图片。余弦以此类推。
            /// <summary>
            /// 正弦曲线Wave扭曲图片
            /// </summary>
            /// <param name="srcBmp"></param>
            /// <param name="bXDir">true左右波动,false上下波动</param>
            /// <param name="nMultValue">波形的幅度倍数</param>
            /// <returns></returns>
            public System.Drawing.Bitmap twistImage(Bitmap srcBmp, bool bXDir, double dMultValue)
            {
                Random rnd = new Random();
                double dPhase = rnd.Next(0, 6);
                System.Drawing.Bitmap destBmp = new Bitmap(srcBmp.Width, srcBmp.Height);
                // 将位图背景填充为白色
                System.Drawing.Graphics graph = System.Drawing.Graphics.FromImage(destBmp);
                graph.FillRectangle(new SolidBrush(System.Drawing.Color.White), 0, 0, destBmp.Width, destBmp.Height);
                graph.Dispose();
                double dBaseAxisLen = bXDir ? (double)destBmp.Height : (double)destBmp.Width;
                for (int i = 0; i < destBmp.Width; i++)
                {
                    for (int j = 0; j < destBmp.Height; j++)
                    {
                        double dx = 0;
                        dx = bXDir ? (Math.PI * 2 * (double)j) / dBaseAxisLen : (Math.PI * 2 * (double)i) / dBaseAxisLen;
                        dx += dPhase;
                        double dy = Math.Sin(dx);
                        // 取得当前点的颜色
                        int nOldX = 0, nOldY = 0;
                        nOldX = bXDir ? i + (int)(dy * dMultValue) : i;
                        nOldY = bXDir ? j : j + (int)(dy * dMultValue);
                        System.Drawing.Color color = srcBmp.GetPixel(i, j);
                        if (nOldX >= 0 && nOldX < destBmp.Width
                         && nOldY >= 0 && nOldY < destBmp.Height)
                        {
                            destBmp.SetPixel(nOldX, nOldY, color);
                        }
                    }
                }
                return destBmp;
            }
     
    总结:在图片处理时,我们大量使用了setpixel和getpixel方法,这仅仅适用于处理小图片,因为这2个方法处理十分缓慢,如果是大图片的话,推荐使用unsafe代码使用指针来进行操作。
    LockBits();在内存中锁定
    Scan0//获取首地址指针
    UnlockBits();在内存中解锁
     
     
    March 11

    .NET学习,生成图片验证码(一)

    最近,在做一个登录界面,界面上想有一个生成随机验证码的功能,就自己实现了一个,主要是使用了GDI+。思路如下:
    1、在内存中生成一张Bitmap图片;
    2、生成随机数字;
    3、Graphics.FromImage()方法获取DC(设备上下文);
    4、Graphics.DrawString();
    5、将图片写入内存流,将内存流通过http传输给网页;
     
    代码如下:
    一、生成图片的网页
        /// <summary>
        /// 生成随机字符串
        /// </summary>
        /// <param name="codeLength">需要生成随机字符串的长度</param>
        /// <returns>生成的字符串</returns>
        private string GenerateCode(int codeLength)
        {
            //存放生成随机数据的字符数组共62个
            char[] charArray = {
                                    '0','1','2','3','4','5','6','7','8','9',
                                    'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
                                    'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'
                                   };
            int arrayLength = charArray.Length;
            string returnValue = "";
            int flag = 0;
            Random rand = new Random();
            //生成制定数字的字符串
            for (int i = 0; i < codeLength; i++)
            {
                while (flag != -1)
                {
                    int pos = rand.Next(0, arrayLength);
                    flag = returnValue.IndexOf(charArray[pos]);
                    if (flag == -1)
                    {
                        returnValue += charArray[pos];
                        flag = 0;
                        break;
                    }
                }
            }
            return returnValue;
        }
     
     
        /// <summary>
        /// 生成验证码图片
        /// </summary>
        /// <param name="ImageWidth">图片宽度</param>
        /// <param name="ImageHeight">图片高度</param>
        /// <param name="font">内容字体</param>
        /// <param name="brush">画刷</param>
        /// <param name="backgroundColor">图片背景色</param>
        /// <param name="codeLength">生成验证码的长度</param>
        /// <returns></returns>
        private MemoryStream GenerateMemoryImage(int ImageWidth, int ImageHeight, Font font, Brush brush, Color backgroundColor, int codeLength)
        {
            MemoryStream ms = new MemoryStream();
            Bitmap image = new Bitmap(ImageWidth, ImageHeight);
            Graphics g = Graphics.FromImage(image);
            g.Clear(backgroundColor);
            string code = GenerateCode(codeLength);
            SizeF size = g.MeasureString(code, font);
            g.DrawString(code, font, brush, (ImageWidth - (int)size.Width) / 2, (ImageHeight - (int)size.Height) / 2);
            image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
            return ms;
        }
     
        //网页调用生成图片方法,并将内存流转换为byte[]通过http传输
        protected void Page_Load(object sender, EventArgs e)
        {
            Font font = new Font("Arial", 20f);
            MemoryStream ms = GenerateMemoryImage(150, 30, font, new SolidBrush(Color.Black), Color.WhiteSmoke, 4);
            Response.ClearContent();
            Response.ContentType = "image/jpeg";
            Response.BinaryWrite(ms.ToArray());
            Response.End();
        }
     
    二、调用图片的网页
    <img id="code" alt="" onclick="this.src='Default.aspx?'+Math.random();" src="Default.aspx" style="padding-left: 10px;
                                            vertical-align: middle; cursor: pointer" />
    只要在需要使用图片的网页上调用该标记即可,之所以="this.src='Default.aspx?'+Math.random();" 要加上Math.random()是因为防止缓存。
     
    生成图片时可以对图片写入的文字,对每个字符/汉字随机使用字体、字号、颜色等等。
     
    下一讲,更深入说明如何对验证码进行图片的效果处理。