图形验证码
平常写网站登录的时候经常会用到图形验证码,做一个小小的总结。
首先最终实现的效果是这样的:
代码实现起来比较简单,随机生成包含字母或数字的四位字符,然后将其画到一个图片里,随后对这个图片做处理,生成噪点、扭曲,最后返回这个图片。思路很简单,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | using System; using System.Collections.Generic; using System.Drawing; using System.Drawing.Imaging; using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; namespace App.Common.ValidateCode { public class GraphicValidateCode { public GraphicValidateCode() { } /// <summary> /// 验证码的最大长度 /// </summary> public int MaxLength { get { return 10; } } /// <summary> /// 验证码的最小长度 /// </summary> public int MinLength { get { return 1; } } private float _fontSize = 14; private int _imageHeight = 26; /// <summary> /// 生成验证码 /// </summary> /// <param name="length">验证码的长度</param> /// <returns></returns> public string GenerateCode( int length) { var codeStr = new StringBuilder(); var random = new Random(); for ( var i = 0; i < length; i++) { string str; var isCharFlag = random.Next(1, length); if (isCharFlag > 1) { str = (( char )random.Next(65, 91)).ToString(); } else { str = random.Next(1, 10).ToString(); } codeStr.Append(str); } return codeStr.ToString(); } #region 生成校验码图片 public Bitmap CreateImageCode( string code) { int fSize = 60; int padding = 2; int fWidth = fSize + padding; var colors = new [] { Color.Black, Color.Red, Color.DarkBlue, Color.Green, Color.Brown, Color.DarkCyan, Color.Purple, Color.Orange }; var fonts = new [] { "Arial" , "Georgia" }; int imageWidth = (code.Length * fWidth) + 4 + padding * 2; int imageHeight = fSize * 2 + padding; Bitmap image = new Bitmap(imageWidth, imageHeight); Graphics g = Graphics.FromImage(image); g.Clear(Color.White); Random rand = new Random(); //给背景添加随机生成的噪点 Pen pen = new Pen(Color.LightBlue, 0); int c = code.Length * 10; for ( int i = 0; i < c; i++) { int x = rand.Next(image.Width); int y = rand.Next(image.Height); g.DrawRectangle(pen, x, y, 1, 1); } int left = 0, top = 0, top1 = 1, top2 = 1; int n1 = (imageHeight - fSize - padding * 2); int n2 = n1 / 4; top1 = n2; top2 = n2 * 2; Font f; Brush b; int cindex, findex; //随机字体和颜色的验证码字符 for ( int i = 0; i < code.Length; i++) { cindex = rand.Next(colors.Length - 1); findex = rand.Next(fonts.Length - 1); f = new System.Drawing.Font(fonts[findex], fSize, System.Drawing.FontStyle.Bold); b = new System.Drawing.SolidBrush(colors[cindex]); if (i % 2 == 1) { top = top2; } else { top = top1; } left = i * fWidth; g.DrawString(code.Substring(i, 1), f, b, left, top); } //画一个边框 边框颜色为Color.Gainsboro g.DrawRectangle( new Pen(Color.Gainsboro, 0), 0, 0, image.Width - 1, image.Height - 1); g.Dispose(); //产生波形(Add By 51aspx.com) image = TwistImage(image, true , 8, 5); return image; } /// <summary> /// 正弦曲线Wave扭曲图片(Edit By 51aspx.com) /// </summary> /// <param name="srcBmp">图片路径</param> /// <param name="bXDir">如果扭曲则选择为True</param> /// <param name="dMultValue">波形的幅度倍数,越大扭曲的程度越高,一般为3</param> /// <param name="dPhase">波形的起始相位,取值区间[0-2*PI)</param> /// <returns></returns> private Bitmap TwistImage(Bitmap srcBmp, bool bXDir, double dMultValue, double dPhase) { const double pi2 = 6.283185307179586476925286766559; var destBmp = new Bitmap(srcBmp.Width, srcBmp.Height); // 将位图背景填充为白色 var graph = Graphics.FromImage(destBmp); graph.FillRectangle( new SolidBrush(Color.White), 0, 0, destBmp.Width, destBmp.Height); graph.Dispose(); double dBaseAxisLen = bXDir ? ( double )destBmp.Height : ( double )destBmp.Width; for ( int i = 0; i < destBmp.Width; i++) { for ( int j = 0; j < destBmp.Height; j++) { double dx = 0; dx = bXDir ? (pi2 * ( double )j) / dBaseAxisLen : (pi2 * ( double )i) / dBaseAxisLen; dx += dPhase; double dy = Math.Sin(dx); // 取得当前点的颜色 int nOldX = 0, nOldY = 0; nOldX = bXDir ? i + ( int )(dy * dMultValue) : i; nOldY = bXDir ? j : j + ( int )(dy * dMultValue); Color color = srcBmp.GetPixel(i, j); if (nOldX >= 0 && nOldX < destBmp.Width && nOldY >= 0 && nOldY < destBmp.Height) { destBmp.SetPixel(nOldX, nOldY, color); } } } return destBmp; } #endregion /// <summary> /// 创建验证码的图片 /// </summary> /// <param name="validateCode"></param> public byte [] GenerateValidateGraphic( string validateCode) { using ( var image = CreateImageCode(validateCode)) { using ( var stream = new MemoryStream()) { image.Save(stream, ImageFormat.Jpeg); //输出图片流 return stream.ToArray(); } } } } public class ValidateCodeValue { /// <summary> /// 校验码 /// </summary> public string Code { get ; set ; } /// <summary> /// 校验失效次数 /// </summary> public int Times { get ; set ; } = 5; } } |
直接以Base64的格式传至页面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /// <summary> /// 获取图片验证码 /// </summary> /// <returns></returns> public ActionResult ValidateIndex() { var validateCode = new GraphicValidateCode(); var code = validateCode.GenerateCode(4); var image = validateCode.GenerateValidateGraphic(code); var base64 = "data:image/jpeg;base64," + Convert.ToBase64String(image); ViewBag.ValidateImg = base64; return View(); } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· PostgreSQL 和 SQL Server 在统计信息维护中的关键差异
· C++代码改造为UTF-8编码问题的总结
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· 实操Deepseek接入个人知识库
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· 【.NET】调用本地 Deepseek 模型
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库