大大毛 的笔记

  DDM's Note

哪怕没有办法一定有说法,
就算没有鸽子一定有乌鸦,
固执无罪 梦想有价,
让他们惊讶.

posts - 14, comments - 23, trackbacks - 0, articles - 58
   :: 首页 ::  :: 联系 ::  :: 管理

生成随机码检验图片

Posted on 2006-08-22 03:00 大大毛 阅读(748) 评论(0)  编辑  收藏 所属分类: ASP.NET

   网页中需要用到这样的功能,参照网上的介绍,做了一个放在这里备查。
   效果图:t_Default7.JPG

   为了方便调用,写成了一个类(RandomCodeImage.cs)。

using  System;
using  System.Drawing;

///   <summary>
///  随机检验码图像模糊度
///   </summary>

public   enum  RandomCodeImageMistily  {
    None 
=   0 ,
    General,
    Deep
}


///   <summary>
///  生成随机校验码图象
///  ddm,2006-8-22
///   </summary>

public   class  RandomCodeImage  {
    
// 随机数
    Random random  =   null ;
    
// 字体
     private   string  fontName  =   null ;
    
// 字体大小
     private   int  fontSize  =   0 ;
    
// 校验码长度
     private   int  codeLength  =   0 ;
    
// 间距
     private   int  codeSpace  =   0 ;
    
// 校验码
     private   string  code  =   null ;
    
// 字体
     private  Font font  =   null ;
    
// 模糊度
     private  RandomCodeImageMistily mistily  =  RandomCodeImageMistily.General;

    
public  RandomCodeImage()  {
        
this .random  =   new  Random();
        
this .fontName  =   " Arial " ;
        
this .fontSize  =   12 ;
        
this .codeLength  =   4 ;
        
this .codeSpace  =   0 ;
    }

    
///   <summary>
    
///  设置/获取字体
    
///   </summary>

     public   string  FontName  {
        
get   {
            
return   this .fontName;
        }

        
set   {
            
this .fontName  =  value;
        }

    }

    
///   <summary>
    
///  设置/获取字体大小
    
///   </summary>

     public   int  FontSize  {
        
get   {
            
return   this .fontSize;
        }

        
set   {
            
this .fontSize  =  value;
        }

    }

    
///   <summary>
    
///  设置/获取校验码的长度
    
///   </summary>

     public   int  CodeLength  {
        
get   {
            
return   this .codeLength;
        }

        
set   {
            
this .codeLength  =  value;
        }

    }

    
///   <summary>
    
///  设置/获取检验码的间距
    
///   </summary>

     public   int  CodeSpace  {
        
get   {
            
return   this .codeSpace;
        }

        
set   {
            
this .codeSpace  =  value;
        }

    }

    
///   <summary>
    
///  设置/获取检验码
    
///   </summary>

     public   string  Code  {
        
get   {
            
if  ( this .code  ==   null {
                
// 生成检验码
                 this .code  =   this .createRandomCode();
            }

            
return   this .code;
        }

        
set   {
            
this .code  =  value;
        }

    }

    
public  RandomCodeImageMistily Mistily  {
        
set   {
            
this .mistily  =  value;
        }

    }


    
///   <summary>
    
///  获取检验码生成的图像
    
///   </summary>

     public  System.Drawing.Bitmap getCodeImage()  {

        
if  ( this .code  ==   null {
            
// 生成检验码
             this .code  =   this .createRandomCode();
        }



        
return   this .createCodeImage();
    }

    
///   <summary>
    
///  获取检验码生成的图像
    
///   </summary>
    
///   <param name="mistily"> 输出图像的模糊度 </param>

     public  System.Drawing.Bitmap getCodeImage(RandomCodeImageMistily mistily)  {
        
this .mistily  =  mistily;
        
return   this .getCodeImage();
    }


    
///   <summary>
    
///  创建随机检验码
    
///   </summary>

     protected   string  createRandomCode()  {
        System.Text.StringBuilder codeBuilder 
=   new  System.Text.StringBuilder();

        
int  ascii  =   0 ;
        
for  ( int  i  =   0 ; i  <   this .codeLength; i ++ {
            
// 0-9,A-Z一共36个
            ascii  =   this .random.Next()  %   36 ;

            
if  (ascii  <   10 {
                
// 数字
                ascii  +=   48 ;
            }
  else   {
                
// 大写字母
                ascii  +=   55 ;
            }


            codeBuilder.Append((
char )ascii);
        }

        
return  codeBuilder.ToString();
    }

    
///   <summary>
    
///  创建代码图像
    
///   </summary>

     private  System.Drawing.Bitmap createCodeImage()  {
        Bitmap tmpImage 
=   null , resultImage  =   null ;
        Graphics tmpG 
=   null , resultG  =   null ;
        
float  charWidth  =  0f, charHeight  =  0f;
        
int  imageWidth  =   0 , imageHeight  =   0 ;
        SizeF size 
=  SizeF.Empty;
        
// 噪音
         int  noiseNum  =   0 ;

        
// 生成字体
         this .font  =   new  Font( this .fontName,  this .fontSize, (FontStyle.Bold  |  FontStyle.Italic), GraphicsUnit.Point);

        
using  (tmpImage  =   new  Bitmap( 1 1 ))  {
            
using  (tmpG  =  Graphics.FromImage(tmpImage))  {
                
// 获得code的输出宽度
                 for  ( int  i  =   0 ; i  <   this .code.Length; i ++ {

                    size 
=  tmpG.MeasureString(code.Substring(i,  1 ), font);
                    charWidth 
+=  size.Width;
                    charHeight 
=  Math.Max(charHeight, size.Height);

                }

            }

        }

        
// 输出字符的大小
        imageWidth  =  ( int )Math.Ceiling(charWidth);
        imageHeight 
=  ( int )Math.Ceiling(charHeight);
        
// 加入间距
        imageWidth  =  imageWidth  +   this .code.Length  *   this .codeSpace  +   this .codeSpace;
        imageHeight 
=  imageHeight  +   2   *   this .codeSpace;
        
// 生成输出图像
        resultImage  =   new  Bitmap(imageWidth, imageHeight);
        
// 画刷,线性颜色渐变画刷,渲染区域是整个图片,从Blue渐变到Pruple,从X轴方面1.2弧度,渐变受角度影响
        Brush brush  =   new  System.Drawing.Drawing2D.LinearGradientBrush( new  Rectangle( 0 0 , resultImage.Width, resultImage.Height), Color.Blue, Color.Purple,  1.2f true );
        
using  (resultG  =  Graphics.FromImage(resultImage))  {
            
// 填充背景色
            resultG.Clear(Color.White);
            
// resultG.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;

            
switch  ( this .mistily)  {
                
case  RandomCodeImageMistily.Deep:
                    noiseNum 
=  resultImage.Width  *  resultImage.Height  /   30 ;
                    
break ;
                
case  RandomCodeImageMistily.General:
                    noiseNum 
=  resultImage.Width  *  resultImage.Height  /   50 ;
                    
break ;
                
default :
                    noiseNum 
=   0 ;
                    
break ;
            }


            
// 画背景噪音线
             for  ( int  i  =   0 ; i  <  noiseNum; i ++ {
                
// 随机坐标
                 int  x1  =  random.Next(resultImage.Width);
                
int  x2  =  random.Next(resultImage.Width);
                
int  y1  =  random.Next(resultImage.Height);
                
int  y2  =  random.Next(resultImage.Height);
                
// 画噪音线
                resultG.DrawLine( new  Pen(Color.Silver), x1, y1, x2, y2);
            }


            
// 画背景噪音点
             for  ( int  i  =   0 ; i  <  noiseNum  *   20 ; i ++ {
                
// 随机坐标
                 int  x  =  random.Next(resultImage.Width);
                
int  y  =  random.Next(resultImage.Height);
                
// 画噪音点
                resultG.DrawEllipse( new  Pen(Color.FromArgb(random.Next())), x, y,  1 1 );
            }

            
// 输出字符
            charWidth  =  charHeight  =   this .codeSpace;
            
for  ( int  i  =   0 ; i  <   this .code.Length; i ++ {
                resultG.DrawString(
this .code.Substring(i,  1 ), font, brush, charWidth, charHeight);
                
// 起始X坐标
                charWidth  =  charWidth  +  resultG.MeasureString( this .code.Substring(i,  1 ), font).Width  +   this .codeSpace;
            }


            
// 画图片边框
            resultG.DrawRectangle( new  Pen(Color.SaddleBrown),  0 0 , resultImage.Width  -   1 , resultImage.Height  -   1 );
        }

        
return  resultImage;
    }

}


   该类实现功能
      能够返回一个随机码检验图片(Image对象),这样可以进行第2次处理。
      属性
      FontName,字体;
      FontSize,字体大小(point);
      CodeLength,随机生成的检验码长度;
      CodeSpace,字间距;
      Code,校验码,如果通过setter设置了该属性,则类不会随机生成新的检验码;
      Mistily,模糊度,效果不是很好。

   在ASP页面中(例ShowCodeImage.aspx)调用类:
    protected void Page_Load(object sender, EventArgs e)
    {
        
//初始化类
        RandomCodeImage r = new RandomCodeImage();
        
//设置字体大小
        r.FontSize = 10;
        
//r.FontName = "Times Now Roman";
        
//设置字间距
        r.CodeSpace = 2;
        
//获取图像
        System.Drawing.Image image = r.getCodeImage();
        
//输出图像
        System.IO.MemoryStream ms = new System.IO.MemoryStream();
        image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
        image.Dispose();
        Response.ContentType 
= "image/Png";
        Response.BinaryWrite(ms.ToArray());

        
//将code放入Session或Cokie用于提交检验
        Session.Add("ddm", r.Code);
    }

   最后在最终需要显示的ASP页面中加以引用:
<img src="ShowCodeImage.aspx" alt="验证图片"/>

   后记:
      在计算字符输出宽度时遇到了麻烦,输出时经常不对头,直到逐步的拆解代码才找到原因。MS在输出字符时,由于各个字符是不等宽的(比如 I 就比较窄),因此在输出时必须先用 Graphics.MeasureString() 方法来计算宽度,但是实际上采用不同的输出方式得到的结果是不同的。如:1.在输出时采用一次性输出整个字符串;2.逐个字符的输出。可以发现各字符的输出宽度之和 要远大于 整个字符串的输出宽度,如果没有考虑到这点就容易产生输出无法定位的情况。

只有注册用户登录后才能发表评论。


网站导航:
 

i am ddm