You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
140 lines
4.4 KiB
140 lines
4.4 KiB
using Microsoft.AspNetCore.Hosting;
|
|
using System;
|
|
using System.Drawing;
|
|
using System.Drawing.Drawing2D;
|
|
using System.Drawing.Imaging;
|
|
using System.Drawing.Text;
|
|
using System.Globalization;
|
|
using System.IO;
|
|
using System.Security.Cryptography;
|
|
|
|
namespace Infrastructure.Web.Mvc
|
|
{
|
|
public class CaptchaHelper : IDisposable
|
|
{
|
|
private readonly PrivateFontCollection _collection;
|
|
|
|
public CaptchaHelper(IWebHostEnvironment env)
|
|
{
|
|
if (env is null)
|
|
{
|
|
throw new ArgumentNullException(nameof(env));
|
|
}
|
|
|
|
_collection = new PrivateFontCollection();
|
|
_collection.AddFontFile(Path.Combine(env.WebRootPath, "fonts", "arial.ttf"));
|
|
}
|
|
|
|
public byte[] GetCaptcha(string code, int width = 80, int height = 30)
|
|
{
|
|
return GetImage(code, width, height);
|
|
}
|
|
|
|
private static Color GetColor()
|
|
{
|
|
var colors = new Color[] {
|
|
Color.DodgerBlue,
|
|
Color.SteelBlue,
|
|
Color.LimeGreen,
|
|
Color.LightSeaGreen,
|
|
Color.DarkGoldenrod,
|
|
Color.Chocolate,
|
|
Color.IndianRed,
|
|
Color.Cyan
|
|
};
|
|
return colors[GetRandom(0, 7)];
|
|
}
|
|
|
|
private byte[] GetImage(string value, int width, int height)
|
|
{
|
|
using var image = DrawImage(value, width, height);
|
|
using var stream = new MemoryStream();
|
|
image.Save(stream, ImageFormat.Jpeg);
|
|
return stream.ToArray();
|
|
}
|
|
|
|
private Bitmap DrawImage(string value, int width, int height)
|
|
{
|
|
var size = new Size(80, 30);
|
|
var image = new Bitmap(size.Width, size.Height);
|
|
var g = Graphics.FromImage(image);
|
|
|
|
g.Clear(Color.FloralWhite);
|
|
using (var pen = new Pen(Color.Lavender))
|
|
{
|
|
g.DrawRectangle(pen, 0, 0, width, height);
|
|
}
|
|
DrawBeziers(g, width, height);
|
|
var top = 0; var left = 0;
|
|
var index = 0;
|
|
DrawChar(value[index++], g, left, top, width, height);
|
|
left += width / 4;
|
|
DrawChar(value[index++], g, left, top, width, height);
|
|
left += width / 4;
|
|
DrawChar(value[index++], g, left, top, width, height);
|
|
left += width / 4;
|
|
DrawChar(value[index++], g, left, top, width, height);
|
|
|
|
return image;
|
|
}
|
|
|
|
private static void DrawBeziers(Graphics g, int width, int height)
|
|
{
|
|
for (int i = 0; i < width * height / 100; i++)
|
|
{
|
|
using var pen = new Pen(GetColor(), 0);
|
|
var x = GetRandom(0, width);
|
|
var y = GetRandom(0, height);
|
|
if (GetRandom() > 4)
|
|
{
|
|
g.DrawEllipse(pen, x, y, GetRandom(), GetRandom());
|
|
}
|
|
else
|
|
{
|
|
g.DrawBezier(pen, x, y, x + 5, y + 5, x + 10, y + 10, x + 20, y + 20);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void DrawChar(char ch, Graphics g, int left, int top, int width, int height)
|
|
{
|
|
var fontSize = 16;
|
|
fontSize += GetRandom(-5, 5);
|
|
var value = ch.ToString(CultureInfo.CurrentCulture);
|
|
using var font = new Font(_collection.Families[0], fontSize);
|
|
var point = new Point(left, top);
|
|
var size = new Size(width, height);
|
|
using var brush = new LinearGradientBrush(new Rectangle(point, size), GetColor(), GetColor(), new Random(DateTime.Now.Millisecond).Next(0, 359));
|
|
g.DrawString(value, font, brush, point);
|
|
}
|
|
|
|
private static int GetRandom(int min = 0, int max = 9)
|
|
{
|
|
var random = new byte[1];
|
|
using (var rg = RandomNumberGenerator.Create())
|
|
{
|
|
rg.GetBytes(random);
|
|
}
|
|
return new Random(Convert.ToInt32(random[0])).Next(min, max);
|
|
}
|
|
|
|
protected virtual void Dispose(bool disposing)
|
|
{
|
|
if (disposing)
|
|
{
|
|
this._collection.Dispose();
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Dispose(true);
|
|
GC.SuppressFinalize(this);
|
|
}
|
|
|
|
~CaptchaHelper()
|
|
{
|
|
Dispose(false);
|
|
}
|
|
}
|
|
} |