使用 System.Drawing 命名空間動態產生包含干擾線、隨機字體/顏色/位移的數字驗證碼圖片,儲存於 Session 供後續驗證。
public class CheckCode
{
// 公開靜態方法:產生驗證碼並輸出圖片
public static void DrawImage()
{
CheckCode instance = new CheckCode();
string code = instance.GenerateRandomCode(4); // 4 位數字
HttpContext.Current.Session["CheckCode"] = code;
instance.RenderImage(code);
}
// 產生不重複隨機數字
private string GenerateRandomCode(int length)
{
string chars = "0,1,2,3,4,5,6,7,8,9";
string[] arr = chars.Split(',');
StringBuilder sb = new StringBuilder();
Random rand = new Random();
int last = -1;
for (int i = 0; i < length; i++)
{
int idx;
do { idx = rand.Next(arr.Length); } while (idx == last);
last = idx;
sb.Append(arr[idx]);
}
return sb.ToString();
}
// 繪製並輸出 JPEG
private void RenderImage(string code)
{
int width = code.Length * 13;
using (Bitmap bmp = new Bitmap(width, 23))
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.White);
// 干擾點
Random rand = new Random();
for (int i = 0; i < 50; i++)
{
g.DrawRectangle(new Pen(Color.LightGray),
rand.Next(width), rand.Next(23), 1, 1);
}
// 字體與顏色陣列
string[] fonts = { "Verdana", "Microsoft Sans Serif", "Comic Sans MS", "Arial", "新細明體" };
Color[] colors = { Color.Black, Color.Red, Color.DarkBlue, Color.Green, Color.Orange, Color.Brown, Color.DarkCyan, Color.Purple };
for (int i = 0; i < code.Length; i++)
{
int cIdx = rand.Next(colors.Length);
int fIdx = rand.Next(fonts.Length);
using (Font font = new Font(fonts[fIdx], 10, FontStyle.Bold))
using (Brush brush = new SolidBrush(colors[cIdx]))
{
int y = (i % 2 == 0) ? 4 : 2; // 錯位效果
g.DrawString(code[i].ToString(), font, brush, 3 + i * 12, y);
}
}
// 邊框
g.DrawRectangle(Pens.Black, 0, 0, width - 1, 22);
// 輸出
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ContentType = "image/jpeg";
using (MemoryStream ms = new MemoryStream())
{
bmp.Save(ms, ImageFormat.Jpeg);
HttpContext.Current.Response.BinaryWrite(ms.ToArray());
}
}
}
}
public partial class CheckCodePage : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
CheckCode.DrawImage();
}
}
<asp:TextBox ID="txtCode" runat="server" Width="150px" />
<img id="imgCaptcha"
src="CheckCode.aspx"
alt="看不清?點擊更換"
style="cursor:pointer; vertical-align:middle;"
onclick="this.src=this.src+'?'+Math.random()" />
<br />
<asp:Button ID="btnSubmit" runat="server" Text="送出" OnClick="btnSubmit_Click" />
protected void btnSubmit_Click(object sender, EventArgs e)
{
string userInput = txtCode.Text.Trim();
string sessionCode = Session["CheckCode"]?.ToString() ?? "";
if (string.Equals(userInput, sessionCode, StringComparison.OrdinalIgnoreCase))
{
// 驗證通過
lblMsg.Text = "驗證成功!";
}
else
{
// 驗證失敗
ClientScript.RegisterStartupScript(this.GetType(), "alert",
"alert('驗證碼錯誤,請重新輸入!');", true);
}
}
System.Drawing.Common (跨平台) 或第三方庫 (如 SkiaSharp, ImageSharp) 避免 GDI+ 記憶體洩漏。