首页 > 代码库 > mvc 如何生成空心3D风格的验证码
mvc 如何生成空心3D风格的验证码
做网站往往少不了要用到图片验证码。虽然现在已经有很多更先进的判断真实用户的手段,但验证码是最基本的一种。
博主要介绍一种用C#生成空心风格验证码的最简单方法,哈哈,真的很简单哦。说来以前我看到腾讯的空心字验证码也是很流口水啊,比默认字体的漂亮太多了,无奈工作太忙一直没有时间尝试,有一些偶然被设计MM提醒了一下,茅塞顿开呀。
实现方法:这里要用到.net framework里面的一个类:PrivateFontCollection,直观的翻成中文就是私有字体集合,msdn上的解释是:
“提供一个字体系列集合,该集合是基于客户端应用程序提供的字体文件生成的。“
也就是说可以在程序中使用自己的字体,那么能不能可web程序 中使用呢,呵呵,当然可以了.
下面就跟博主一步步来实现吧
1、创建一个类,CaptchaController,继承自Controller,返回图片的方法为Show
public class CaptchaController : Controller { // // GET: /Captcha/ public ActionResult Show(int? len, int? w,int? h) { } }
接下来添加两个私有成员
PrivateFontCollection privateFontCollection = new PrivateFontCollection(); FontFamily[] _families = { };
PrivateFontCollection将为我们加载空心字体
2、下载空心字体,引入到代码中,到哪里去下载呢,当然是百度了,不过博主是找公司的设计MM要的,毕竟她们整天接触这个,下面是博主找到的三个空心字体文件,可以把它们放在app_data文件夹里。
接下来直接引用到代码中
privateFontCollection.AddFontFile(Server.MapPath("/App_Data/swisscbo.ttf")); privateFontCollection.AddFontFile(Server.MapPath("/App_Data/LARSON.TTF")); privateFontCollection.AddFontFile(Server.MapPath("/App_Data/AgentRed.TTF")); //new FontFamily("Acidic"), // new FontFamily("Rosewood Std"), _families = privateFontCollection.Families;
3、生成随机码,方法如下
private string RandomCode(int count) { Random rand = new Random((int)now.Ticks / 20000); String allChar = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; Char[] allCharArray = allChar.ToCharArray(); String randomCode = ""; for (int i = 0; i < count; i++) { int t = rand.Next(35); randomCode = String.Concat(randomCode, Char.ToString(allCharArray[t])); } return randomCode; }
4、开始画图,代码如下
public Bitmap GenerateImage(string text, Size size) { VXin.Core.RandomNumbers rand = new VXin.Core.RandomNumbers(); // Create the new Bitmap of the specified size and render to it Bitmap bmp = new Bitmap(size.Width, size.Height); using (Graphics g = Graphics.FromImage(bmp)) { g.SmoothingMode = SmoothingMode.AntiAlias; //使绘图质量最高,即消除锯齿 g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.CompositingQuality = CompositingQuality.HighQuality; //Draw the background with a white brush using (Brush b = new SolidBrush(Color.FromArgb(0xec, 0xf8, 0xff))) { g.FillRectangle(b, 0, 0, bmp.Width, bmp.Height); } // Select a font family and create the default sized font. We then need to shrink // the font size until the text fits. FontFamily ff = _families[rand.Next(_families.Length)]; int emSize = (int)(size.Width * 2.5 / text.Length); Font f = new Font(ff, emSize); try { // Make sure that the font size we have will fit with the selected text. SizeF measured = new SizeF(0, 0); SizeF workingSize = new SizeF(size.Width, size.Height); while (emSize > 2 && (measured = g.MeasureString(text, f)).Width > workingSize.Width || measured.Height > workingSize.Height) { f.Dispose(); f = new Font(ff, emSize -= 2, FontStyle.Bold); } // Select a color and draw the string into the center of the image using (StringFormat fmt = new StringFormat()) { fmt.Alignment = fmt.LineAlignment = StringAlignment.Center; using (Brush b = new LinearGradientBrush( new Rectangle(0, 0, size.Width / 2, size.Height / 2), _colors[rand.Next(_colors.Length)], _colors[rand.Next(_colors.Length)], (float)(rand.NextDouble() * 360), false)) { g.DrawString(text, f, b, new Rectangle(0, 5, bmp.Width, bmp.Height), fmt); } } } finally { // Clean up f.Dispose(); } } return bmp; }
5、到这里画图这一步就完成了,输入应该是一个比较规整的显示字母的图片,但这是不是我想要的验证码啊,验证码不是防止机器识别的吗,不要急,接下来通过最后一步,使图片扭曲,如何扭曲呢,博主打算给它来个波浪型变幻,也就是正弦变幻啦,怎么做到呢,呵呵,用笨方法,挪动每个相素的位置,大家如果有好的办法也可以在下面留言,代码如下
private static void DistortImage(Bitmap b, double distortion)
{
int width = b.Width, height = b.Height;
// Copy the image so that we‘re always using the original for source color
using (Bitmap copy = (Bitmap)b.Clone())
{
// Iterate over every pixel
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
// Adds a simple wave
int newX = (int)(x + (distortion * Math.Sin(Math.PI * y / 64.0)));
int newY = (int)(y + (distortion * Math.Cos(Math.PI * x / 64.0)));
if (newX < 0 || newX >= width) newX = 0;
if (newY < 0 || newY >= height) newY = 0;
b.SetPixel(x, y, copy.GetPixel(newX, newY));
}
}
}
}
6、完整代码
public class CaptchaController : Controller { // // GET: /Captcha/ public ActionResult Show(int? len, int? w,int? h) { privateFontCollection.AddFontFile(Server.MapPath("/App_Data/swisscbo.ttf")); privateFontCollection.AddFontFile(Server.MapPath("/App_Data/LARSON.TTF")); privateFontCollection.AddFontFile(Server.MapPath("/App_Data/AgentRed.TTF")); _families = privateFontCollection.Families; if (!len.HasValue) len = 5; var code = RandomCode(len); var bmpOut = GenerateImage(code, new Size(90, 42)); var ms = new MemoryStream(); bmpOut.Save(ms, ImageFormat.Png); var bmpBytes = ms.GetBuffer(); bmpOut.Dispose(); ms.Close(); privateFontCollection.Dispose(); Session["Captcha"] = code; return File(bmpBytes, @"image/jpeg"); } /// <summary>Generates the challenge image.</summary> /// <param name="text">The text to be rendered into the image.</param> /// <param name="size">The size of the image to generate.</param> /// <returns>A dynamically-generated challenge image.</returns> public Bitmap GenerateImage(string text, Size size) { VXin.Core.RandomNumbers rand = new VXin.Core.RandomNumbers(); // Create the new Bitmap of the specified size and render to it Bitmap bmp = new Bitmap(size.Width, size.Height); using (Graphics g = Graphics.FromImage(bmp)) { g.SmoothingMode = SmoothingMode.AntiAlias; //使绘图质量最高,即消除锯齿 g.InterpolationMode = InterpolationMode.HighQualityBicubic; g.CompositingQuality = CompositingQuality.HighQuality; //Draw the background with a white brush using (Brush b = new SolidBrush(Color.FromArgb(0xec, 0xf8, 0xff))) { g.FillRectangle(b, 0, 0, bmp.Width, bmp.Height); } // Select a font family and create the default sized font. We then need to shrink // the font size until the text fits. FontFamily ff = _families[rand.Next(_families.Length)]; int emSize = (int)(size.Width * 2.5 / text.Length); Font f = new Font(ff, emSize); try { // Make sure that the font size we have will fit with the selected text. SizeF measured = new SizeF(0, 0); SizeF workingSize = new SizeF(size.Width, size.Height); while (emSize > 2 && (measured = g.MeasureString(text, f)).Width > workingSize.Width || measured.Height > workingSize.Height) { f.Dispose(); f = new Font(ff, emSize -= 2, FontStyle.Bold); } // Select a color and draw the string into the center of the image using (StringFormat fmt = new StringFormat()) { fmt.Alignment = fmt.LineAlignment = StringAlignment.Center; using (Brush b = new LinearGradientBrush( new Rectangle(0, 0, size.Width / 2, size.Height / 2), _colors[rand.Next(_colors.Length)], _colors[rand.Next(_colors.Length)], (float)(rand.NextDouble() * 360), false)) { g.DrawString(text, f, b, new Rectangle(0, 5, bmp.Width, bmp.Height), fmt); } } } finally { // Clean up f.Dispose(); } } // Distort the final image and return it. This distortion amount is fairly arbitrary. DistortImage(bmp, rand.Next(5, 10) * (rand.Next(2) == 1 ? 1 : -1)); using (Graphics g = Graphics.FromImage(bmp)) { using (var pen = new Pen(Color.FromArgb(0xd7, 0xed, 0xfa))) { g.DrawRectangle(pen, new Rectangle(0, 0, bmp.Width - 1, bmp.Height - 1)); } } return bmp; } /// <summary>Distorts the image.</summary> /// <param name="b">The image to be transformed.</param> /// <param name="distortion">An amount of distortion.</param> private static void DistortImage(Bitmap b, double distortion) { int width = b.Width, height = b.Height; // Copy the image so that we‘re always using the original for source color using (Bitmap copy = (Bitmap)b.Clone()) { // Iterate over every pixel for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // Adds a simple wave int newX = (int)(x + (distortion * Math.Sin(Math.PI * y / 64.0))); int newY = (int)(y + (distortion * Math.Cos(Math.PI * x / 64.0))); if (newX < 0 || newX >= width) newX = 0; if (newY < 0 || newY >= height) newY = 0; b.SetPixel(x, y, copy.GetPixel(newX, newY)); } } } } private string RandomCode(int count) { Random rand = new Random((int)now.Ticks / 20000); String allChar = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; Char[] allCharArray = allChar.ToCharArray(); String randomCode = ""; for (int i = 0; i < count; i++) { int t = rand.Next(35); randomCode = String.Concat(randomCode, Char.ToString(allCharArray[t])); } return randomCode; } private static Color[] _colors = { Color.ForestGreen, Color.FromArgb(0,68, 0xA3), Color.FromArgb(10, 0x1f, 28), Color.FromArgb(0xe8, 0,0), Color.FromArgb(84, 0x0b, 0x0b), Color.FromArgb(0x1f, 84, 0x0b), Color.FromArgb(11, 65, 01), Color.FromArgb(79, 0x2c, 0x8f), Color.FromArgb(0x0d, 01, 65) }; /// <summary>List of fonts that can be used for rendering text.</summary> /// <remarks>This list can be changed to include any families available on the current system.</remarks> PrivateFontCollection privateFontCollection = new PrivateFontCollection(); private FontFamily[] _families = { }; }
好了,现在可以把这段程序应用到自己网站上了,刷新一下,显示的应该是这样
也可以是这样
还可以是这样
以及这样
每次显示的曲线都不一样哦,还是空心3D字体,看上去是不是很拉轰呢
mvc 如何生成空心3D风格的验证码