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.
iot/projects/Infrastructure/Web/Mvc/CaptchaHelper.cs

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);
}
}
}