|
@@ -12,12 +12,6 @@ using SixLabors.ImageSharp.PixelFormats;
|
|
|
using ZhonTai.Admin.Core.Attributes;
|
|
|
using ZhonTai.Admin.Tools.Cache;
|
|
|
|
|
|
-/*
|
|
|
-Linux下Ubuntu如果报Gdip错误,需要按照以下步骤操作
|
|
|
-1. apt-get install libgdiplus
|
|
|
-2. cd /usr/lib
|
|
|
-3. ln -s libgdiplus.so gdiplus.dll
|
|
|
-*/
|
|
|
namespace ZhonTai.Admin.Tools.Captcha
|
|
|
{
|
|
|
/// <summary>
|
|
@@ -28,6 +22,8 @@ namespace ZhonTai.Admin.Tools.Captcha
|
|
|
{
|
|
|
private readonly ICacheTool _cache;
|
|
|
|
|
|
+ private readonly Random _random = new();
|
|
|
+
|
|
|
public SlideJigsawCaptchaTool(ICacheTool cache)
|
|
|
{
|
|
|
_cache = cache;
|
|
@@ -39,9 +35,9 @@ namespace ZhonTai.Admin.Tools.Captcha
|
|
|
/// <param name="startNum"></param>
|
|
|
/// <param name="endNum"></param>
|
|
|
/// <returns></returns>
|
|
|
- private static int GetRandomInt(int startNum, int endNum)
|
|
|
+ private int GetRandomInt(int startNum, int endNum)
|
|
|
{
|
|
|
- return (endNum > startNum ? new Random().Next(endNum - startNum) : 0) + startNum;
|
|
|
+ return (endNum > startNum ? _random.Next(endNum - startNum) : 0) + startNum;
|
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
@@ -52,9 +48,8 @@ namespace ZhonTai.Admin.Tools.Captcha
|
|
|
/// <param name="templateWidth"></param>
|
|
|
/// <param name="templateHeight"></param>
|
|
|
/// <returns></returns>
|
|
|
- private static PointModel GeneratePoint(int originalWidth, int originalHeight, int templateWidth, int templateHeight)
|
|
|
+ private PointModel GeneratePoint(int originalWidth, int originalHeight, int templateWidth, int templateHeight)
|
|
|
{
|
|
|
- var random = new Random();
|
|
|
int widthDifference = originalWidth - templateWidth;
|
|
|
int heightDifference = originalHeight - templateHeight;
|
|
|
int x;
|
|
@@ -64,7 +59,7 @@ namespace ZhonTai.Admin.Tools.Captcha
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- x = random.Next(originalWidth - templateWidth - 100) + 100;
|
|
|
+ x = _random.Next(originalWidth - templateWidth - 100) + 100;
|
|
|
}
|
|
|
|
|
|
int y;
|
|
@@ -74,7 +69,7 @@ namespace ZhonTai.Admin.Tools.Captcha
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- y = random.Next(originalHeight - templateHeight - 5) + 5;
|
|
|
+ y = _random.Next(originalHeight - templateHeight - 5) + 5;
|
|
|
}
|
|
|
|
|
|
return new PointModel(x, y);
|
|
@@ -90,7 +85,7 @@ namespace ZhonTai.Admin.Tools.Captcha
|
|
|
/// <param name="blockX"></param>
|
|
|
/// <param name="blockY"></param>
|
|
|
/// <returns></returns>
|
|
|
- private static PointModel GenerateInterferencePoint(int originalWidth, int originalHeight, int templateWidth, int templateHeight, int blockX, int blockY)
|
|
|
+ private PointModel GenerateInterferencePoint(int originalWidth, int originalHeight, int templateWidth, int templateHeight, int blockX, int blockY)
|
|
|
{
|
|
|
int x;
|
|
|
if (originalWidth - blockX - 5 > templateWidth * 2)
|
|
@@ -119,13 +114,13 @@ namespace ZhonTai.Admin.Tools.Captcha
|
|
|
return new PointModel(x, y);
|
|
|
}
|
|
|
|
|
|
- private static ComplexPolygon CalcBlockShape(Image<Rgba32> holeTemplateImage)
|
|
|
+ private static ComplexPolygon CalcBlockShape(Image<Rgba32> templateDarkImage)
|
|
|
{
|
|
|
int temp = 0;
|
|
|
var pathList = new List<IPath>();
|
|
|
- holeTemplateImage.ProcessPixelRows(accessor =>
|
|
|
+ templateDarkImage.ProcessPixelRows(accessor =>
|
|
|
{
|
|
|
- for (int y = 0; y < holeTemplateImage.Height; y++)
|
|
|
+ for (int y = 0; y < templateDarkImage.Height; y++)
|
|
|
{
|
|
|
var rowSpan = accessor.GetRowSpan(y);
|
|
|
for (int x = 0; x < rowSpan.Length; x++)
|
|
@@ -156,7 +151,8 @@ namespace ZhonTai.Admin.Tools.Captcha
|
|
|
/// <summary>
|
|
|
/// 获得验证数据
|
|
|
/// </summary>
|
|
|
- /// <returns>JObject</returns>
|
|
|
+ /// <param name="captchaKey"></param>
|
|
|
+ /// <returns></returns>
|
|
|
public async Task<CaptchaOutput> GetAsync(string captchaKey)
|
|
|
{
|
|
|
//获取网络图片
|
|
@@ -165,45 +161,57 @@ namespace ZhonTai.Admin.Tools.Captcha
|
|
|
//client.Dispose();
|
|
|
|
|
|
//底图
|
|
|
- using var baseImage = await Image.LoadAsync<Rgba32>($@"{Directory.GetCurrentDirectory()}\wwwroot\captcha\jigsaw\{new Random().Next(1, 4)}.jpg".ToPath());
|
|
|
- //模板图
|
|
|
- using var templateImage = await Image.LoadAsync<Rgba32>($@"{Directory.GetCurrentDirectory()}\wwwroot\captcha\jigsaw\templates\{new Random().Next(1, 7)}.png".ToPath());
|
|
|
+ using var baseImage = await Image.LoadAsync<Rgba32>($@"{Directory.GetCurrentDirectory()}\wwwroot\captcha\jigsaw\backgrounds\{_random.Next(1, 6)}.jpg".ToPath());
|
|
|
+ var randomTemplate = _random.Next(1, 7);
|
|
|
+ //深色模板图
|
|
|
+ using var darkTemplateImage = await Image.LoadAsync<Rgba32>($@"{Directory.GetCurrentDirectory()}\wwwroot\captcha\jigsaw\templates\{randomTemplate}\dark.png".ToPath());
|
|
|
+ //透明模板图
|
|
|
+ using var transparentTemplateImage = await Image.LoadAsync<Rgba32>($@"{Directory.GetCurrentDirectory()}\wwwroot\captcha\jigsaw\templates\{randomTemplate}\transparent.png".ToPath());
|
|
|
|
|
|
int baseWidth = baseImage.Width;
|
|
|
int baseHeight = baseImage.Height;
|
|
|
- int templateWidth = templateImage.Width;
|
|
|
- int templateHeight = templateImage.Height;
|
|
|
+ int blockWidth = 50;
|
|
|
+ int blockHeight = 50;
|
|
|
|
|
|
- //拼图
|
|
|
- using var blockImage = new Image<Rgba32>(templateWidth, templateHeight);
|
|
|
- //滑块拼图
|
|
|
- using var sliderBlockImage = new Image<Rgba32>(templateWidth, baseHeight);
|
|
|
+ //调整模板图大小
|
|
|
+ darkTemplateImage.Mutate(x =>
|
|
|
+ {
|
|
|
+ x.Resize(blockWidth, blockHeight);
|
|
|
+ });
|
|
|
+ transparentTemplateImage.Mutate(x =>
|
|
|
+ {
|
|
|
+ x.Resize(blockWidth, blockHeight);
|
|
|
+ });
|
|
|
+
|
|
|
+ //新建拼图
|
|
|
+ using var blockImage = new Image<Rgba32>(blockWidth, blockHeight);
|
|
|
+ //新建滑块拼图
|
|
|
+ using var sliderBlockImage = new Image<Rgba32>(blockWidth, baseHeight);
|
|
|
|
|
|
//随机生成拼图坐标
|
|
|
- PointModel blockPoint = GeneratePoint(baseWidth, baseHeight, templateWidth, templateHeight);
|
|
|
+ PointModel blockPoint = GeneratePoint(baseWidth, baseHeight, blockWidth, blockHeight);
|
|
|
+
|
|
|
+ //根据深色模板图计算轮廓形状
|
|
|
+ var blockShape = CalcBlockShape(darkTemplateImage);
|
|
|
|
|
|
- //根据模板图计算轮廓
|
|
|
- var blockShape = CalcBlockShape(templateImage);
|
|
|
//生成拼图
|
|
|
blockImage.Mutate(x =>
|
|
|
{
|
|
|
x.Clip(blockShape, p => p.DrawImage(baseImage, new Point(-blockPoint.X, -blockPoint.Y), 1));
|
|
|
});
|
|
|
- //叠加拼图
|
|
|
- //blockImage.Mutate(x => x.DrawImage(templateImage, new Point(0, 0), 1));
|
|
|
+ //拼图叠加透明模板图层
|
|
|
+ blockImage.Mutate(x => x.DrawImage(transparentTemplateImage, new Point(0, 0), 1));
|
|
|
|
|
|
//生成滑块拼图
|
|
|
sliderBlockImage.Mutate(x => x.DrawImage(blockImage, new Point(0, blockPoint.Y), 1));
|
|
|
|
|
|
- //生成拼图底图
|
|
|
- baseImage.Mutate(x => x.DrawImage(templateImage, new Point(blockPoint.X, blockPoint.Y), (float)0.5));
|
|
|
-
|
|
|
+ //底图叠加深色模板图
|
|
|
+ baseImage.Mutate(x => x.DrawImage(darkTemplateImage, new Point(blockPoint.X, blockPoint.Y), 0.5f));
|
|
|
//生成干扰图坐标
|
|
|
- PointModel interferencePoint = GenerateInterferencePoint(baseWidth, baseHeight, templateWidth, templateHeight, blockPoint.X, blockPoint.Y);
|
|
|
-
|
|
|
- //生成干扰图底图
|
|
|
- baseImage.Mutate(x => x.DrawImage(templateImage, new Point(interferencePoint.X, interferencePoint.Y), (float)0.5));
|
|
|
-
|
|
|
+ PointModel interferencePoint = GenerateInterferencePoint(baseWidth, baseHeight, blockWidth, blockHeight, blockPoint.X, blockPoint.Y);
|
|
|
+ //底图叠加深色干扰模板图
|
|
|
+ baseImage.Mutate(x => x.DrawImage(darkTemplateImage, new Point(interferencePoint.X, interferencePoint.Y), 0.5f));
|
|
|
+
|
|
|
var token = Guid.NewGuid().ToString();
|
|
|
var captchaData = new CaptchaOutput
|
|
|
{
|