验证码实现(中文+变形+噪点)

为了应付越来越多的自动发帖机、恶意攻击等情形,验证码技术在大量的网站上得到使用。我在近期开发一个注册网站的时候,也使用了这一技术。当然,我并不想完完全全自己重新实现,而是参考了网上能够找到的实现,做了若干改进而已。下面谈谈我的实现。
    补两张图片:
      
    首先看验证码图片输出页的代码:

<% @ Page Language = " C# "   %>

<! DOCTYPE html PUBLIC  " -//W3C//DTD XHTML 1.0 Transitional//EN "   " http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd " >

< script runat = " server " >
    
protected   void  Page_Load( object  sender, EventArgs e)
    {
        VryImgGen gen 
=   new  VryImgGen();
        
string  verifyCode  =  gen.CreateVerifyCode( 5 1 );
        Session[
" VerifyCode " =  verifyCode.ToUpper();
        System.Drawing.Bitmap bitmap 
=  gen.CreateImage(verifyCode);
        System.IO.MemoryStream ms 
=   new  System.IO.MemoryStream();
        bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
        Response.Clear();
        Response.ContentType 
=   " image/Png " ;
        Response.BinaryWrite(ms.GetBuffer());
        bitmap.Dispose();
        ms.Dispose();
        ms.Close();
        Response.End();
    }
</ script >

    功能很简单,初始化一个验证码生成对象,生成图片。然后保存到一个MemoryStream里。得到字节流,输出字节流。验证码的数据是保存在Session中的,这是最简单的方法。或者可以加密储存在cookie里,也是可以的。

    再来看看验证码生成对象:

using  System;
using  System.Data;
using  System.Configuration;
using  System.Web;
using  System.Web.Security;
using  System.Web.UI;
using  System.Web.UI.WebControls;
using  System.Web.UI.WebControls.WebParts;
using  System.Web.UI.HtmlControls;
using  System.Drawing;
using  System.Text;

///   <summary>
///  Summary description for VryImgGen
///   </summary>
public   partial   class  VryImgGen
{
    
    
///   <summary>
    
///  供验证码生成汉字时选取的汉字集,若为空则按照《GB2312简体中文编码表》编码规则构造汉字
    
///   </summary>
     public   static   string  ChineseChars  =  String.Empty;

    
///   <summary>
    
///  英文与数字串
    
///   </summary>
     protected   static   readonly   string  EnglishOrNumChars  =   " 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ " ;
   
    
public  VryImgGen()
    {
        rnd 
=   new  Random( unchecked (( int )DateTime.Now.Ticks));
    }

    
///   <summary>
    
///  全局随机数生成器
    
///   </summary>
     private  Random rnd;
    
    
int  length  =   5 ;
    
///   <summary>
    
///  验证码长度(默认6个验证码的长度)
    
///   </summary>
     public   int  Length
    {
        
get  {  return  length; }
        
set  { length  =  value; }
    }
        
    
int  fontSize  =   18 ;
    
///   <summary>
    
///  验证码字体大小(为了显示扭曲效果,默认30像素,可以自行修改)
    
///   </summary>
     public   int  FontSize
    {
        
get  {  return  fontSize; }
        
set  { fontSize  =  value; }
    }   
    
    
int  padding  =   4 ;
    
///   <summary>
    
///  边框补(默认4像素)
    
///   </summary>
     public   int  Padding
    {
        
get  {  return  padding; }
        
set  { padding  =  value; }
    }   
    
    
bool  chaos  =   true ;
    
///   <summary>
    
///  是否输出燥点(默认输出)
    
///   </summary>
     public   bool  Chaos
    {
        
get  {  return  chaos; }
        
set  { chaos  =  value; }
    }   
        
    Color chaosColor 
=  Color.LightGray;
    
///   <summary>
    
///  输出燥点的颜色(默认灰色)
    
///   </summary>
     public  Color ChaosColor
    {
        
get  {  return  chaosColor; }
        
set  { chaosColor  =  value; }
    }
    
    Color backgroundColor 
=  Color.White;
    
///   <summary>
    
///  自定义背景色(默认白色)
    
///   </summary>
     public  Color BackgroundColor
    {
        
get  {  return  backgroundColor; }
        
set  { backgroundColor  =  value; }
    }   
        
    Color[] colors 
=  { Color.Black, Color.Red, Color.DarkBlue, Color.Green, Color.Orange, Color.Brown, Color.DarkCyan, Color.Purple };
    
///   <summary>
    
///  自定义随机颜色数组
    
///   </summary>
     public  Color[] Colors
    {
        
get  {  return  colors; }
        
set  { colors  =  value; }
    }
  
    
string [] fonts  =  {  " Arial " " Georgia "  };
    
///   <summary>
    
///  自定义字体数组
    
///   </summary>
     public   string [] Fonts
    {
        
get  {  return  fonts; }
        
set  { fonts  =  value; }
    }   

    
#region  产生波形滤镜效果

    
private   const   double  PI  =   3.1415926535897932384626433832795 ;
    
private   const   double  PI2  =   6.283185307179586476925286766559 ;

    
///   <summary>
    
///  正弦曲线Wave扭曲图片(Edit By 51aspx.com)
    
///   </summary>
    
///   <param name="srcBmp"> 图片路径 </param>
    
///   <param name="bXDir"> 如果扭曲则选择为True </param>
    
///   <param name="nMultValue"> 波形的幅度倍数,越大扭曲的程度越高,一般为3 </param>
    
///   <param name="dPhase"> 波形的起始相位,取值区间[0-2*PI) </param>
    
///   <returns></returns>
     public  System.Drawing.Bitmap TwistImage(Bitmap srcBmp,  bool  bXDir,  double  dMultValue,  double  dPhase)
    {
        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  ?  (PI2  *  ( double )j)  /  dBaseAxisLen : (PI2  *  ( 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;
    }



    
#endregion
   
    
///   <summary>
    
///  生成校验码图片
    
///   </summary>
    
///   <param name="code"> 验证码 </param>
    
///   <returns></returns>
     public  Bitmap CreateImage( string  code)
    {
        
int  fSize  =  FontSize;
        
int  fWidth  =  fSize  +  Padding;

        
int  imageWidth  =  ( int )(code.Length  *  fWidth)  +   4   +  Padding  *   2 ;
        
int  imageHeight  =  fSize  *   2   +  Padding  *   2 ;

        System.Drawing.Bitmap image 
=   new  System.Drawing.Bitmap(imageWidth, imageHeight);

        Graphics g 
=  Graphics.FromImage(image);

        g.Clear(BackgroundColor);

        
// 给背景添加随机生成的燥点
         if  ( this .Chaos)
        {

            Pen pen 
=   new  Pen(ChaosColor,  0 );
            
int  c  =  Length  *   10 ;

            
for  ( int  i  =   0 ; i  <  c; i ++ )
            {
                
int  x  =  rnd.Next(image.Width);
                
int  y  =  rnd.Next(image.Height);

                g.DrawRectangle(pen, x, y, 
1 1 );
            }
        }

        
int  left  =   0 , top  =   0 , top1  =   1 , top2  =   1 ;

        
int  n1  =  (imageHeight  -  FontSize  -  Padding  *   2 );
        
int  n2  =  n1  /   4 ;
        top1 
=  n2;
        top2 
=  n2  *   2 ;

        Font f;
        Brush b;

        
int  cindex, findex;

        
// 随机字体和颜色的验证码字符
         for  ( int  i  =   0 ; i  <  code.Length; i ++ )
        {
            cindex 
=  rnd.Next(Colors.Length  -   1 );
            findex 
=  rnd.Next(Fonts.Length  -   1 );

            f 
=   new  System.Drawing.Font(Fonts[findex], fSize, System.Drawing.FontStyle.Bold);
            b 
=   new  System.Drawing.SolidBrush(Colors[cindex]);

            
if  (i  %   2   ==   1 )
            {
                top 
=  top2;
            }
            
else
            {
                top 
=  top1;
            }

            left 
=  i  *  fWidth;

            g.DrawString(code.Substring(i, 
1 ), f, b, left, top);
        }

        
// 画一个边框 边框颜色为Color.Gainsboro
        g.DrawRectangle( new  Pen(Color.Gainsboro,  0 ),  0 0 , image.Width  -   1 , image.Height  -   1 );
        g.Dispose();

        
// 产生波形(Add By 51aspx.com)
        image  =  TwistImage(image,  true 8 4 );

        
return  image;
    }
            
    
///   <summary>
    
///  生成随机字符码
    
///   </summary>
    
///   <param name="codeLen"> 字符串长度 </param>
    
///   <param name="zhCharsCount"> 中文字符数 </param>
    
///   <returns></returns>
     public   string  CreateVerifyCode( int  codeLen,  int  zhCharsCount)
    {
        
char [] chs  =   new   char [codeLen];

        
int  index;
        
for  ( int  i  =   0 ; i  <  zhCharsCount; i ++ )
        {
            index 
=  rnd.Next( 0 , codeLen);
            
if  (chs[index]  ==   '

   这里面大量使用了51aspx.com的代码,在此表示感谢。这里的主要改进在于支持生成中英文混合的验证码。中文的生成有两种方式,一是根据《GB2312简体中文编码表》编码规则构造汉字,二是从一个选定的中文字符集合中随即选取汉字。实现很简单,参考函数protected char CreateZhChar(),在此不赘述。

    最后说一下验证码的使用,下面是一个例子:
   这里有个小技巧,就是在刷新验证码的使用,验证码的URL后面用了随机参数以欺骗浏览器重新请求。

< img  src ="VerifyCode.aspx"  id ="valiCode"  alt ="验证码"   />
< title ="刷新验证码"  href ="#"  onclick ="javascript:document.getElementById('valiCode').src='VerifyCode.aspx?id='+Math.random();return false;" > 看不清,换张图片? </ a >

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值