大家都知道驗(yàn)證碼是以圖片形式展示的,而且是動(dòng)態(tài)生成的,這樣就需要我們?nèi)ギ?huà)出它,那不得不提到是GDI+繪圖了
科普一下,什么是GDI+?
GDI+是圖形設(shè)備接口(GDI)的高級(jí)版本, 提供了各種豐富的圖形圖像處理功能。GDI+主要由二維矢量圖形、圖像處理和版式3部分組成。GDI+為使用各種字體、字號(hào)和樣式來(lái)顯示文本這種復(fù)雜任務(wù)提供了大量的支持。
下面說(shuō)說(shuō)驗(yàn)證碼,對(duì)于驗(yàn)證碼這樣的圖片,我覺(jué)得是由兩部分組成的,一部分是矩形的背景,另一部分是在其上的字母數(shù)字組合(有的時(shí)候有漢字,有的時(shí)候是純字母或者純數(shù)字,這個(gè)沒(méi)有統(tǒng)一規(guī)定,怎么選擇看你~)。對(duì)于矩形的背景我們可以直接把其當(dāng)成畫(huà)布,字母數(shù)字組合呢?我們可以利用隨機(jī)數(shù)去拼出一組新組合。這樣整個(gè)過(guò)程我們都想好了,下面看下代碼吧:
聲明一下,我寫(xiě)的這個(gè)驗(yàn)證碼為5個(gè)字符長(zhǎng)度,由大小寫(xiě)英文字母+數(shù)字隨機(jī)組合。
private readonly char[] constant = {
'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'};//一個(gè)由數(shù)字和大小寫(xiě)英文字母組成的字符數(shù)組
protected void Page_Load(object sender, EventArgs e)
{
Bitmap bitmap = new Bitmap(100, 25);//創(chuàng)建一個(gè)位圖,寬100,高25,就是我所說(shuō)的第一部分,矩形背景
Graphics g = Graphics.FromImage(bitmap);//創(chuàng)建畫(huà)布
g.Clear(Color.YellowGreen);//為畫(huà)布填充黃綠色
Font font1 = new Font("Arial", 15);//設(shè)置字體類型和大小
Brush brush = new SolidBrush(Color.Blue);//設(shè)置畫(huà)刷顏色
Pen myPen = new Pen(Color.Blue, 5);//創(chuàng)建畫(huà)筆對(duì)象
StringBuilder random = new StringBuilder(5); //創(chuàng)建可變字符串對(duì)象,用于存放隨機(jī)生成的驗(yàn)證碼
Random rd = new Random();//創(chuàng)建一個(gè)隨機(jī)數(shù)生成器對(duì)象
for (int i = 0; i random.Capacity; i++)
{
random.Append(constant[rd.Next(62)]);//生成一個(gè)隨機(jī)字符加到random里
}
g.DrawString(random.ToString(), font1, brush, 10, 5);//在畫(huà)布上畫(huà)出字符串
System.IO.MemoryStream ms = new System.IO.MemoryStream();//創(chuàng)建數(shù)據(jù)流MemoryStream
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);//指定圖像的輸出格式為gif
Response.ClearContent();
Response.ContentType = "image/Gif";
Response.BinaryWrite(ms.ToArray());//輸出二進(jìn)制數(shù)據(jù)流
}
生成的效果是這樣的:

大家可能會(huì)覺(jué)得這樣看起來(lái)很容易辨識(shí),跟我們平時(shí)登錄網(wǎng)站時(shí)輸入的驗(yàn)證碼比起來(lái)有點(diǎn)像個(gè)小學(xué)生。當(dāng)然,我們可以做些改變,比較加上一定的角度。
private readonly char[] constant = {
'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'};//一個(gè)由數(shù)字和大小寫(xiě)英文字母組成的字符數(shù)組
protected void Page_Load(object sender, EventArgs e)
{
Bitmap bitmap = new Bitmap(100, 25);//創(chuàng)建一個(gè)位圖,寬100,高25,就是我所說(shuō)的第一部分,矩形背景
Graphics g = Graphics.FromImage(bitmap);//創(chuàng)建畫(huà)布
g.Clear(Color.YellowGreen);//為畫(huà)布填充黃綠色
Font font1 = new Font("Arial", 15);//設(shè)置字體類型和大小
float angle = 60;//旋轉(zhuǎn)的一個(gè)基礎(chǔ)角度
float length = 0;//顯示字符的基礎(chǔ)位置,往后看
Brush brush = new SolidBrush(Color.Blue);//設(shè)置畫(huà)刷顏色
Pen myPen = new Pen(Color.Blue, 5);//創(chuàng)建畫(huà)筆對(duì)象
StringBuilder random = new StringBuilder(5); //創(chuàng)建可變字符串對(duì)象,用于存放隨機(jī)生成的驗(yàn)證碼
Random rd = new Random();//創(chuàng)建一個(gè)隨機(jī)數(shù)生成器對(duì)象
for (int i = 0; i random.Capacity; i++)
{
random.Append(constant[rd.Next(62)]);//生成一個(gè)隨機(jī)字符加到random里
g.ResetTransform();//將畫(huà)布重置矩陣
SizeF size = g.MeasureString(random[random.Length - 1].ToString(), font1);//得到新生成字符的尺寸
g.TranslateTransform(length + size.Width / 2, size.Height / 2);//選擇此次旋轉(zhuǎn)的中心位置
g.RotateTransform((float)rd.NextDouble() * angle * 2 - angle);//進(jìn)行隨機(jī)角度旋轉(zhuǎn)
g.DrawString(random[random.Length - 1].ToString(), font1, brush, new PointF(-size.Width / 2, -size.Height / 2));//注意,這里不是前一個(gè)例子,一次性把5個(gè)字符全部畫(huà)出來(lái),而是一個(gè)一個(gè)畫(huà)
length += size.Width;//保證下次畫(huà)字符的位置不會(huì)覆蓋前一次的字符
}
System.IO.MemoryStream ms = new System.IO.MemoryStream();//創(chuàng)建數(shù)據(jù)流MemoryStream
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Gif);//指定圖像的輸出格式為gif
Response.ClearContent();
Response.ContentType = "image/Gif";
Response.BinaryWrite(ms.ToArray());//輸出二進(jìn)制數(shù)據(jù)流
}
這時(shí)生成的效果是這樣的:

是不是看起來(lái)更專業(yè)一些了呢?如果大家還是覺(jué)得不滿意的話,可以看下GDI+的相關(guān)內(nèi)容,通過(guò)添加一些噪點(diǎn)的元素,或者刪除線這樣子的東西來(lái)達(dá)到提高識(shí)別難度的目的,我這里就不一一列舉啦。
關(guān)于如何畫(huà)驗(yàn)證碼我們說(shuō)過(guò)了,但是還有兩點(diǎn)問(wèn)題我還是想多說(shuō)一下。
1、我們實(shí)際輸出的是一個(gè)二進(jìn)制的流,如何做到顯示到頁(yè)面上與頁(yè)面其他元素共存呢?
這里通用的一種方法就是把畫(huà)驗(yàn)證碼的這段代碼放到一個(gè)獨(dú)立的Web窗體頁(yè)中,在另一個(gè)需要顯示驗(yàn)證碼的頁(yè)面放一個(gè)img>元素,把其src屬性指向該驗(yàn)證碼頁(yè)的url。比如我寫(xiě)的一段是這樣:
復(fù)制代碼 代碼如下:
asp:Image ID="image_validatecode" runat="server" ImageUrl="~/PublicMethod/ValidateCode.aspx" style="padding-left:3px"/>
其實(shí)這里我是用大家通用的方法,不過(guò)我先前也有單獨(dú)寫(xiě)一個(gè)web自定義控件,專門生成驗(yàn)證碼使用,但是當(dāng)拖入到頁(yè)面中后運(yùn)行,它還是會(huì)把頁(yè)面其他元素給覆蓋掉,具體原因我也不清楚。
2、驗(yàn)證碼主要目的還是用于驗(yàn)證使用的,所以我們?cè)谟脩裘?,密碼是否合法外,同時(shí)也要判斷當(dāng)前輸入的驗(yàn)證碼是不是與圖片上的驗(yàn)證碼一致。
我上面的代碼中并沒(méi)有寫(xiě)這塊,其實(shí)只要在隨機(jī)生成最終驗(yàn)證碼之后,把其值存入一個(gè)session中去就可以了。然后在判斷用戶名,密碼的同時(shí)去比較一下這個(gè)session值就OK了。如:
復(fù)制代碼 代碼如下:
Session["login_validate_code"] = random.ToString();
3、如何用戶沒(méi)有看清此張驗(yàn)證碼,想換一張如何實(shí)現(xiàn)?
可以通過(guò)腳本給img元素的src屬性重新賦值url實(shí)現(xiàn),當(dāng)然,麻煩點(diǎn)的話也可以使用ajax去實(shí)現(xiàn)。大家可以自己試試。
以上就是本文給大家分享的制作驗(yàn)證碼的全部過(guò)程,希望大家能夠喜歡。
您可能感興趣的文章:- ASP.NET驗(yàn)證碼實(shí)現(xiàn)(附源碼)
- asp.net驗(yàn)證碼的簡(jiǎn)單制作
- ASP.NET驗(yàn)證碼(3種)
- asp.net之生成驗(yàn)證碼的方法集錦(一)
- asp.net驗(yàn)證碼圖片生成示例
- ASP.NET MVC驗(yàn)證碼功能實(shí)現(xiàn)代碼
- asp.net生成驗(yàn)證碼(純數(shù)字)
- asp.net ajax實(shí)現(xiàn)無(wú)刷新驗(yàn)證碼
- 封裝的一個(gè)asp.net驗(yàn)證碼類
- ASP.NET中的無(wú)刷新驗(yàn)證碼的開(kāi)發(fā)(完整代碼)
- asp.net簡(jiǎn)單生成驗(yàn)證碼的方法