每个字符旋转随机角度的可视验证码
验证码大概如下:
------------------------
------------------------
------------------------
演示网站下载:Click me to DOWNLOAD
验证码多种多样,为了防止被机器识别,通常都会加入干扰元素,如绘制干扰线、干扰点、背景图片,还有让字符扭曲、旋转字符等等。
我个人认为验证扭曲或旋转字符这样的干扰元素比较好,因为加入干扰线,背景图片虽然强悍,但有时可能连人都认不出来,这个会让网站显得很不友好,用户不禁火大:(。
要实现扭曲验证码必须图象大一些(至少要每字符至少要40*40的尺寸)才看地清楚,但有时我们的需求可能不允许让一个如此大尺寸的图象,此时,何不考虑用旋转的形式呢?!
旋转验证码思路不难,分几步就可以完成:
C# 代码如下:
------------------------
------------------------
------------------------
演示网站下载:Click me to DOWNLOAD
验证码多种多样,为了防止被机器识别,通常都会加入干扰元素,如绘制干扰线、干扰点、背景图片,还有让字符扭曲、旋转字符等等。
我个人认为验证扭曲或旋转字符这样的干扰元素比较好,因为加入干扰线,背景图片虽然强悍,但有时可能连人都认不出来,这个会让网站显得很不友好,用户不禁火大:(。
要实现扭曲验证码必须图象大一些(至少要每字符至少要40*40的尺寸)才看地清楚,但有时我们的需求可能不允许让一个如此大尺寸的图象,此时,何不考虑用旋转的形式呢?!
旋转验证码思路不难,分几步就可以完成:
- 遍历随机字符,每个字符生成一个图象
- 旋转每一个字符图象
- 将所有字符图象拼接成一个图象
C# 代码如下:
using System;
using System.Drawing;
using System.Web;
namespace Oran.Image
{
/// <summary>
/// 旋转的可视验证码图象
/// </summary>
public class RotatedVlidationCode
{
public enum RandomStringMode
{
/// <summary>
/// 小写字母
/// </summary>
LowerLetter,
/// <summary>
/// 大写字母
/// </summary>
UpperLetter,
/// <summary>
/// 混合大小写字母
/// </summary>
Letter,
/// <summary>
/// 数字
/// </summary>
Digital,
/// <summary>
/// 混合数字与大小字母
/// </summary>
Mix
}
public static string GenerateRandomString(int length, RandomStringMode mode)
{
string rndStr = string.Empty;
if (length == 0)
return rndStr;
//以数组方式候选字符,可以更方便的剔除不要的字符,如数字 0 与字母 o
char[] digitals = new char[10] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
char[] lowerLetters = new char[26] {
'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' };
char[] upperLetters = new char[26] {
'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' };
char[] letters = new char[52]{
'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' };
char[] mix = new char[62]{
'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[] range = new int[2] { 0, 0 };
Random random = new Random();
switch (mode)
{
case RandomStringMode.Digital:
for (int i = 0; i < length; ++i)
rndStr += digitals[random.Next(0, digitals.Length)];
break;
case RandomStringMode.LowerLetter:
for (int i = 0; i < length; ++i)
rndStr += lowerLetters[random.Next(0, lowerLetters.Length)];
break;
case RandomStringMode.UpperLetter:
for (int i = 0; i < length; ++i)
rndStr += upperLetters[random.Next(0, upperLetters.Length)];
break;
case RandomStringMode.Letter:
for (int i = 0; i < length; ++i)
rndStr += letters[random.Next(0, letters.Length)];
break;
default:
for (int i = 0; i < length; ++i)
rndStr += mix[random.Next(0, mix.Length)];
break;
}
return rndStr;
}
/// <summary>
/// 显示验证码
/// </summary>
/// <param name="seed">随机数辅助种子</param>
/// <param name="strLen">验证码字符长度</param>
/// <param name="fontSize">字体大小</param>
/// <param name="mode">随机字符模式</param>
/// <param name="clrFont">字体颜色</param>
/// <param name="clrBg">背景颜色</param>
public static void ShowValidationCode(ref int seed, int strLen, int fontSize, RandomStringMode mode, Color clrFont, Color clrBg)
{
int tmpSeed;
unchecked
{
tmpSeed = (int)(seed * DateTime.Now.Ticks);
++seed;
}
Random rnd = new Random(tmpSeed);
string text = GenerateRandomString(strLen, mode);
int height = fontSize * 2;
int width = height * text.Length;
Bitmap bmp = new Bitmap(width, height);
Graphics graphics = Graphics.FromImage(bmp);
Font font = new Font("Courier New", fontSize, FontStyle.Bold);
Brush brush = new SolidBrush(clrFont);
Brush brushBg = new SolidBrush(clrBg);
graphics.FillRectangle(brushBg, 0, 0, width, height);
Bitmap tmpBmp = new Bitmap(height, width / text.Length);
Graphics tmpGph = null;
int degree = 40;
Point tmpPoint = new Point();
for (int i = 0; i < text.Length; i++)
{
tmpBmp = new Bitmap(height, width / text.Length);
tmpGph = Graphics.FromImage(tmpBmp);
tmpGph.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
tmpGph.FillRectangle(brushBg, 0, 0, tmpBmp.Width, tmpBmp.Height);
degree = rnd.Next(20, 51); // [20, 50]随机角度
if (rnd.Next(0, 2) == 0)
{
tmpPoint.X = 12; // 调整文本坐标以适应旋转后的图象
tmpPoint.Y = -6;
}
else
{
degree = ~degree + 1; // 逆时针旋转
tmpPoint.X = -10;
tmpPoint.Y = 6;
}
tmpGph.RotateTransform(degree);
tmpGph.DrawString(text[i].ToString(), font, brush, tmpPoint);
graphics.DrawImage(tmpBmp, i * tmpBmp.Width, 0); // 拼接图象
}
//输出图象
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
bmp.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Gif);
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ContentType = "image/gif";
HttpContext.Current.Response.BinaryWrite(memoryStream.ToArray());
HttpContext.Current.Response.End();
//释放资源
font.Dispose();
brush.Dispose();
brushBg.Dispose();
tmpGph.Dispose();
tmpBmp.Dispose();
graphics.Dispose();
bmp.Dispose();
memoryStream.Dispose();
}
}
}
using System.Drawing;
using System.Web;
namespace Oran.Image
{
/// <summary>
/// 旋转的可视验证码图象
/// </summary>
public class RotatedVlidationCode
{
public enum RandomStringMode
{
/// <summary>
/// 小写字母
/// </summary>
LowerLetter,
/// <summary>
/// 大写字母
/// </summary>
UpperLetter,
/// <summary>
/// 混合大小写字母
/// </summary>
Letter,
/// <summary>
/// 数字
/// </summary>
Digital,
/// <summary>
/// 混合数字与大小字母
/// </summary>
Mix
}
public static string GenerateRandomString(int length, RandomStringMode mode)
{
string rndStr = string.Empty;
if (length == 0)
return rndStr;
//以数组方式候选字符,可以更方便的剔除不要的字符,如数字 0 与字母 o
char[] digitals = new char[10] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
char[] lowerLetters = new char[26] {
'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' };
char[] upperLetters = new char[26] {
'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' };
char[] letters = new char[52]{
'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' };
char[] mix = new char[62]{
'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[] range = new int[2] { 0, 0 };
Random random = new Random();
switch (mode)
{
case RandomStringMode.Digital:
for (int i = 0; i < length; ++i)
rndStr += digitals[random.Next(0, digitals.Length)];
break;
case RandomStringMode.LowerLetter:
for (int i = 0; i < length; ++i)
rndStr += lowerLetters[random.Next(0, lowerLetters.Length)];
break;
case RandomStringMode.UpperLetter:
for (int i = 0; i < length; ++i)
rndStr += upperLetters[random.Next(0, upperLetters.Length)];
break;
case RandomStringMode.Letter:
for (int i = 0; i < length; ++i)
rndStr += letters[random.Next(0, letters.Length)];
break;
default:
for (int i = 0; i < length; ++i)
rndStr += mix[random.Next(0, mix.Length)];
break;
}
return rndStr;
}
/// <summary>
/// 显示验证码
/// </summary>
/// <param name="seed">随机数辅助种子</param>
/// <param name="strLen">验证码字符长度</param>
/// <param name="fontSize">字体大小</param>
/// <param name="mode">随机字符模式</param>
/// <param name="clrFont">字体颜色</param>
/// <param name="clrBg">背景颜色</param>
public static void ShowValidationCode(ref int seed, int strLen, int fontSize, RandomStringMode mode, Color clrFont, Color clrBg)
{
int tmpSeed;
unchecked
{
tmpSeed = (int)(seed * DateTime.Now.Ticks);
++seed;
}
Random rnd = new Random(tmpSeed);
string text = GenerateRandomString(strLen, mode);
int height = fontSize * 2;
int width = height * text.Length;
Bitmap bmp = new Bitmap(width, height);
Graphics graphics = Graphics.FromImage(bmp);
Font font = new Font("Courier New", fontSize, FontStyle.Bold);
Brush brush = new SolidBrush(clrFont);
Brush brushBg = new SolidBrush(clrBg);
graphics.FillRectangle(brushBg, 0, 0, width, height);
Bitmap tmpBmp = new Bitmap(height, width / text.Length);
Graphics tmpGph = null;
int degree = 40;
Point tmpPoint = new Point();
for (int i = 0; i < text.Length; i++)
{
tmpBmp = new Bitmap(height, width / text.Length);
tmpGph = Graphics.FromImage(tmpBmp);
tmpGph.TextRenderingHint = System.Drawing.Text.TextRenderingHint.ClearTypeGridFit;
tmpGph.FillRectangle(brushBg, 0, 0, tmpBmp.Width, tmpBmp.Height);
degree = rnd.Next(20, 51); // [20, 50]随机角度
if (rnd.Next(0, 2) == 0)
{
tmpPoint.X = 12; // 调整文本坐标以适应旋转后的图象
tmpPoint.Y = -6;
}
else
{
degree = ~degree + 1; // 逆时针旋转
tmpPoint.X = -10;
tmpPoint.Y = 6;
}
tmpGph.RotateTransform(degree);
tmpGph.DrawString(text[i].ToString(), font, brush, tmpPoint);
graphics.DrawImage(tmpBmp, i * tmpBmp.Width, 0); // 拼接图象
}
//输出图象
System.IO.MemoryStream memoryStream = new System.IO.MemoryStream();
bmp.Save(memoryStream, System.Drawing.Imaging.ImageFormat.Gif);
HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
HttpContext.Current.Response.ClearContent();
HttpContext.Current.Response.ContentType = "image/gif";
HttpContext.Current.Response.BinaryWrite(memoryStream.ToArray());
HttpContext.Current.Response.End();
//释放资源
font.Dispose();
brush.Dispose();
brushBg.Dispose();
tmpGph.Dispose();
tmpBmp.Dispose();
graphics.Dispose();
bmp.Dispose();
memoryStream.Dispose();
}
}
}