using SixLabors.Fonts; using SixLabors.ImageSharp; using SixLabors.ImageSharp.Drawing; using SixLabors.ImageSharp.Drawing.Processing; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using System; using System.IO; using System.Numerics; namespace Wood.Util { public class CaptchaHelper { #region 得到验证码 /// /// Tuple第一个值是表达式,第二个值是表达式结果 /// /// public static Tuple GetCaptchaCode() { int value = 0; char[] operators = { '+', '-', '*' }; string randomCode = string.Empty; Random random = new Random(); int first = random.Next() % 10; int second = random.Next() % 10; char operatorChar = operators[random.Next(0, operators.Length)]; switch (operatorChar) { case '+': value = first + second; break; case '-': // 第1个数要大于第二个数 if (first < second) { int temp = first; first = second; second = temp; } value = first - second; break; case '*': value = first * second; break; } char code = (char)('0' + (char)first); randomCode += code; randomCode += operatorChar; code = (char)('0' + (char)second); randomCode += code; randomCode += "=?"; return new Tuple(randomCode, value); } #endregion #region 生成验证码图片 /// /// 生成验证码图片 /// /// 验证码字符串 /// 包含验证码图片的字节数组 public static byte[] CreateCaptchaImage(string randomCode) { const int randAngle = 45; // 随机转动角度 FontFamily fontFamily = SystemFonts.Collection.Get("Verdana"); var font = fontFamily.CreateFont(36, FontStyle.Regular | FontStyle.Bold); // 计算文本的尺寸 var textSize = TextMeasurer.MeasureSize(randomCode, new TextOptions(font)); int mapWidth = (int)(textSize.Width + 10); int mapHeight = (int)(textSize.Height + 10); int singleCodeWidth = mapWidth / randomCode.Length; int paddingTop = 3; var aliceBlue = new Rgba32(240, 248, 255); using var image = new Image(mapWidth, mapHeight, aliceBlue); var random = new Random(); // 绘制干扰曲线 for (int i = 0; i < 2; i++) { PointF p1 = new(0, random.Next(mapHeight)); PointF p2 = new(random.Next(mapWidth), random.Next(mapHeight)); PointF p3 = new(random.Next(mapWidth), random.Next(mapHeight)); PointF p4 = new(mapWidth, random.Next(mapHeight)); var path = new PathBuilder(); path.AddCubicBezier(p1, p2, p3, p4); image.Mutate(x => x.Draw(Color.Gray, 1f, path.Build())); } // 定义颜色和字体 Color[] colors = { Color.Black, Color.Red, Color.DarkBlue, Color.Green, Color.Orange, Color.Brown, Color.DarkCyan, Color.Purple }; float x = 3; // 起始位置 foreach (char t in randomCode) { int cIndex = random.Next(colors.Length); var color = colors[cIndex]; // 加减乘运算符不进行旋转 if (t == '+' || t == '-' || t == '*' || t == '=') { // 加减乘运算符不进行旋转 image.Mutate(ctx => ctx.DrawText(t.ToString(), font, color, new PointF(x, paddingTop))); } else { float angle = random.Next(-randAngle, randAngle + 1); // 确保包括正负randAngle // 创建一个变换矩阵用于旋转文本 var transform = Matrix3x2.CreateRotation((float)Math.PI * angle / 180, new PointF(x + singleCodeWidth / 2, paddingTop + textSize.Height / 2)); // 设置绘图选项并应用变换矩阵 var drawingOptions = new DrawingOptions { Transform = transform, GraphicsOptions = new GraphicsOptions() { Antialias = true, ColorBlendingMode = PixelColorBlendingMode.Normal } }; // 绘制变换后的文本 image.Mutate(ctx => ctx.DrawText(drawingOptions, t.ToString(), font, color, new PointF(x, paddingTop)) ); } x += singleCodeWidth; // 移动到下一个字符的位置 } // 将图像保存为 GIF 格式并返回字节数组 using var ms = new MemoryStream(); image.Save(ms, new PngEncoder()); return ms.ToArray(); } #endregion } }