|  | @@ -1,12 +1,16 @@
 | 
	
		
			
				|  |  | -using ZhonTai.Admin.Tools.Cache;
 | 
	
		
			
				|  |  | -using Newtonsoft.Json;
 | 
	
		
			
				|  |  | +using Newtonsoft.Json;
 | 
	
		
			
				|  |  |  using System;
 | 
	
		
			
				|  |  | -using System.Drawing;
 | 
	
		
			
				|  |  | -using System.Drawing.Drawing2D;
 | 
	
		
			
				|  |  | -using System.Drawing.Imaging;
 | 
	
		
			
				|  |  |  using System.IO;
 | 
	
		
			
				|  |  |  using System.Threading.Tasks;
 | 
	
		
			
				|  |  | +using System.Collections.Generic;
 | 
	
		
			
				|  |  | +using SixLabors.ImageSharp;
 | 
	
		
			
				|  |  | +using SixLabors.ImageSharp.Drawing.Processing;
 | 
	
		
			
				|  |  | +using SixLabors.ImageSharp.Processing;
 | 
	
		
			
				|  |  | +using SixLabors.ImageSharp.Formats.Png;
 | 
	
		
			
				|  |  | +using SixLabors.ImageSharp.Drawing;
 | 
	
		
			
				|  |  | +using SixLabors.ImageSharp.PixelFormats;
 | 
	
		
			
				|  |  |  using ZhonTai.Admin.Core.Attributes;
 | 
	
		
			
				|  |  | +using ZhonTai.Admin.Tools.Cache;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  /*
 | 
	
		
			
				|  |  |  Linux下Ubuntu如果报Gdip错误,需要按照以下步骤操作
 | 
	
	
		
			
				|  | @@ -29,253 +33,6 @@ namespace ZhonTai.Admin.Tools.Captcha
 | 
	
		
			
				|  |  |              _cache = cache;
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        /// Bitmap转为base64编码的文本
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <param name="bmp"></param>
 | 
	
		
			
				|  |  | -        /// <returns></returns>
 | 
	
		
			
				|  |  | -        private string ImgToBase64String(Bitmap bmp)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            try
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                MemoryStream ms = new MemoryStream();
 | 
	
		
			
				|  |  | -                bmp.Save(ms, ImageFormat.Png);
 | 
	
		
			
				|  |  | -                byte[] arr = new byte[ms.Length];
 | 
	
		
			
				|  |  | -                ms.Position = 0;
 | 
	
		
			
				|  |  | -                ms.Read(arr, 0, (int)ms.Length);
 | 
	
		
			
				|  |  | -                ms.Close();
 | 
	
		
			
				|  |  | -                return Convert.ToBase64String(arr);
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            catch
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                return null;
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        /// 读取像素
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <param name="img"></param>
 | 
	
		
			
				|  |  | -        /// <param name="x"></param>
 | 
	
		
			
				|  |  | -        /// <param name="y"></param>
 | 
	
		
			
				|  |  | -        /// <param name="pixels"></param>
 | 
	
		
			
				|  |  | -        private void ReadPixel(Bitmap img, int x, int y, int[] pixels)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            int xStart = x - 1;
 | 
	
		
			
				|  |  | -            int yStart = y - 1;
 | 
	
		
			
				|  |  | -            int current = 0;
 | 
	
		
			
				|  |  | -            for (int i = xStart; i < 3 + xStart; i++)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                for (int j = yStart; j < 3 + yStart; j++)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    int tx = i;
 | 
	
		
			
				|  |  | -                    if (tx < 0)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        tx = -tx;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    else if (tx >= img.Width)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        tx = x;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    int ty = j;
 | 
	
		
			
				|  |  | -                    if (ty < 0)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        ty = -ty;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    else if (ty >= img.Height)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        ty = y;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    pixels[current++] = img.GetPixel(tx, ty).ToArgb();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        private void FillMatrix(int[][] matrix, int[] values)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            int filled = 0;
 | 
	
		
			
				|  |  | -            for (int i = 0; i < matrix.Length; i++)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                int[] x = matrix[i];
 | 
	
		
			
				|  |  | -                for (int j = 0; j < x.Length; j++)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    x[j] = values[filled++];
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        private Color AvgMatrix(int[][] matrix)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            int r = 0;
 | 
	
		
			
				|  |  | -            int g = 0;
 | 
	
		
			
				|  |  | -            int b = 0;
 | 
	
		
			
				|  |  | -            for (int i = 0; i < matrix.Length; i++)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                int[] x = matrix[i];
 | 
	
		
			
				|  |  | -                for (int j = 0; j < x.Length; j++)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    if (j == 1)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        continue;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                    Color c = Color.FromArgb(x[j]);
 | 
	
		
			
				|  |  | -                    r += c.R;
 | 
	
		
			
				|  |  | -                    g += c.G;
 | 
	
		
			
				|  |  | -                    b += c.B;
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            return Color.FromArgb(r / 8, g / 8, b / 8);
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        /// 根据模板生成拼图
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <param name="baseImage"></param>
 | 
	
		
			
				|  |  | -        /// <param name="templateImage"></param>
 | 
	
		
			
				|  |  | -        /// <param name="x"></param>
 | 
	
		
			
				|  |  | -        /// <param name="y"></param>
 | 
	
		
			
				|  |  | -        /// <returns></returns>
 | 
	
		
			
				|  |  | -        private Bitmap CutByTemplate(Bitmap baseImage, Bitmap templateImage, int x, int y)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            //生成透明背景图
 | 
	
		
			
				|  |  | -            Bitmap newImage = new Bitmap(templateImage.Width, baseImage.Height);
 | 
	
		
			
				|  |  | -            for (int i = 0, newImageWidth = templateImage.Width; i < newImageWidth; i++)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                for (int j = 0, newImageHeight = baseImage.Height; j < newImageHeight; j++)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    newImage.SetPixel(i, j, Color.FromArgb(0,0,0,0));
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            // 临时数组遍历用于高斯模糊存周边像素值
 | 
	
		
			
				|  |  | -            int[] values = new int[9];
 | 
	
		
			
				|  |  | -            int[][] martrix = { new int[3], new int[3], new int[3] };
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            int xLength = templateImage.Width;
 | 
	
		
			
				|  |  | -            int yLength = templateImage.Height;
 | 
	
		
			
				|  |  | -            // 模板图像宽度
 | 
	
		
			
				|  |  | -            for (int i = 0; i < xLength; i++)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                // 模板图片高度
 | 
	
		
			
				|  |  | -                for (int j = 0; j < yLength; j++)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    // 如果模板图像当前像素点不是透明色 copy源文件信息到目标图片中
 | 
	
		
			
				|  |  | -                    int rgb = templateImage.GetPixel(i, j).ToArgb();
 | 
	
		
			
				|  |  | -                    if (rgb < 0)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        Color oriImageColor = baseImage.GetPixel(x + i, y + j);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                        newImage.SetPixel(i, y + j, oriImageColor);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                        //抠图区域半透明
 | 
	
		
			
				|  |  | -                        //baseImage.SetPixel(x + i, y + j, Color.FromArgb(120, oriImageColor.R, oriImageColor.G, oriImageColor.B));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                        //抠图区域高斯模糊
 | 
	
		
			
				|  |  | -                        ReadPixel(baseImage, x + i, y + j, values);
 | 
	
		
			
				|  |  | -                        FillMatrix(martrix, values);
 | 
	
		
			
				|  |  | -                        baseImage.SetPixel(x + i, y + j, AvgMatrix(martrix));
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    //防止数组越界判断
 | 
	
		
			
				|  |  | -                    if (i == (xLength - 1) || j == (yLength - 1))
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        continue;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    int rightRgb = templateImage.GetPixel(i + 1, j).ToArgb();
 | 
	
		
			
				|  |  | -                    int downRgb = templateImage.GetPixel(i, j + 1).ToArgb();
 | 
	
		
			
				|  |  | -                    //描边处理,,取带像素和无像素的界点,判断该点是不是临界轮廓点,如果是设置该坐标像素是白色
 | 
	
		
			
				|  |  | -                    if ((rgb >= 0 && rightRgb < 0) || (rgb < 0 && rightRgb >= 0) || (rgb >= 0 && downRgb < 0) || (rgb < 0 && downRgb >= 0))
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        newImage.SetPixel(i, y + j, Color.White);
 | 
	
		
			
				|  |  | -                        baseImage.SetPixel(x + i, y + j, Color.White);
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            return newImage;
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        /// 根据模板生成干扰图
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <param name="baseImage"></param>
 | 
	
		
			
				|  |  | -        /// <param name="templateImage"></param>
 | 
	
		
			
				|  |  | -        /// <param name="x"></param>
 | 
	
		
			
				|  |  | -        /// <param name="y"></param>
 | 
	
		
			
				|  |  | -        private void InterferenceByTemplate(Bitmap baseImage, Bitmap templateImage, int x, int y)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            // 临时数组遍历用于高斯模糊存周边像素值
 | 
	
		
			
				|  |  | -            int[][] martrix = { new int[3], new int[3], new int[3] };
 | 
	
		
			
				|  |  | -            int[] values = new int[9];
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            int xLength = templateImage.Width;
 | 
	
		
			
				|  |  | -            int yLength = templateImage.Height;
 | 
	
		
			
				|  |  | -            // 模板图像宽度
 | 
	
		
			
				|  |  | -            for (int i = 0; i < xLength; i++)
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                // 模板图片高度
 | 
	
		
			
				|  |  | -                for (int j = 0; j < yLength; j++)
 | 
	
		
			
				|  |  | -                {
 | 
	
		
			
				|  |  | -                    // 如果模板图像当前像素点不是透明色 copy源文件信息到目标图片中
 | 
	
		
			
				|  |  | -                    int rgb = templateImage.GetPixel(i, j).ToArgb();
 | 
	
		
			
				|  |  | -                    if (rgb < 0)
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        Color oriImageColor = baseImage.GetPixel(x + i, y + j);
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                        //抠图区域半透明
 | 
	
		
			
				|  |  | -                        //baseImage.SetPixel(x + i, y + j, Color.FromArgb(120, oriImageColor.R, oriImageColor.G, oriImageColor.B));
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                        //抠图区域高斯模糊
 | 
	
		
			
				|  |  | -                        ReadPixel(baseImage, x + i, y + j, values);
 | 
	
		
			
				|  |  | -                        FillMatrix(martrix, values);
 | 
	
		
			
				|  |  | -                        baseImage.SetPixel(x + i, y + j, AvgMatrix(martrix));
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    //防止数组越界判断
 | 
	
		
			
				|  |  | -                    if (i == (xLength - 1) || j == (yLength - 1))
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        continue;
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                    int rightRgb = templateImage.GetPixel(i + 1, j).ToArgb();
 | 
	
		
			
				|  |  | -                    int downRgb = templateImage.GetPixel(i, j + 1).ToArgb();
 | 
	
		
			
				|  |  | -                    //描边处理,,取带像素和无像素的界点,判断该点是不是临界轮廓点,如果是设置该坐标像素是白色
 | 
	
		
			
				|  |  | -                    if ((rgb >= 0 && rightRgb < 0) || (rgb < 0 && rightRgb >= 0) || (rgb >= 0 && downRgb < 0) || (rgb < 0 && downRgb >= 0))
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        baseImage.SetPixel(x + i, y + j, Color.White);
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                }
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -        
 | 
	
		
			
				|  |  | -        /// <summary>
 | 
	
		
			
				|  |  | -        /// 更改图片尺寸
 | 
	
		
			
				|  |  | -        /// </summary>
 | 
	
		
			
				|  |  | -        /// <param name="bmp"></param>
 | 
	
		
			
				|  |  | -        /// <param name="width"></param>
 | 
	
		
			
				|  |  | -        /// <param name="height"></param>
 | 
	
		
			
				|  |  | -        /// <returns></returns>
 | 
	
		
			
				|  |  | -        private Bitmap ResizeImage(Bitmap bmp, int width, int height)
 | 
	
		
			
				|  |  | -        {
 | 
	
		
			
				|  |  | -            try
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                Bitmap b = new Bitmap(width, height);
 | 
	
		
			
				|  |  | -                Graphics g = Graphics.FromImage(b);
 | 
	
		
			
				|  |  | -                // 图画质量
 | 
	
		
			
				|  |  | -                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
 | 
	
		
			
				|  |  | -                g.DrawImage(bmp, new Rectangle(0, 0, width, height), new Rectangle(0, 0, bmp.Width, bmp.Height), GraphicsUnit.Pixel);
 | 
	
		
			
				|  |  | -                g.Dispose();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -                return b;
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -            catch
 | 
	
		
			
				|  |  | -            {
 | 
	
		
			
				|  |  | -                return null;
 | 
	
		
			
				|  |  | -            }
 | 
	
		
			
				|  |  | -        }
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  |          /// <summary>
 | 
	
		
			
				|  |  |          /// 随机范围内数字
 | 
	
		
			
				|  |  |          /// </summary>
 | 
	
	
		
			
				|  | @@ -362,6 +119,40 @@ namespace ZhonTai.Admin.Tools.Captcha
 | 
	
		
			
				|  |  |              return new PointModel(x, y);
 | 
	
		
			
				|  |  |          }
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +        private static ComplexPolygon CalcBlockShape(Image<Rgba32> holeTemplateImage)
 | 
	
		
			
				|  |  | +        {
 | 
	
		
			
				|  |  | +            int temp = 0;
 | 
	
		
			
				|  |  | +            var pathList = new List<IPath>();
 | 
	
		
			
				|  |  | +            holeTemplateImage.ProcessPixelRows(accessor =>
 | 
	
		
			
				|  |  | +            {
 | 
	
		
			
				|  |  | +                for (int y = 0; y < holeTemplateImage.Height; y++)
 | 
	
		
			
				|  |  | +                {
 | 
	
		
			
				|  |  | +                    var rowSpan = accessor.GetRowSpan(y);
 | 
	
		
			
				|  |  | +                    for (int x = 0; x < rowSpan.Length; x++)
 | 
	
		
			
				|  |  | +                    {
 | 
	
		
			
				|  |  | +                        ref Rgba32 pixel = ref rowSpan[x];
 | 
	
		
			
				|  |  | +                        if (pixel.A != 0)
 | 
	
		
			
				|  |  | +                        {
 | 
	
		
			
				|  |  | +                            if (temp == 0)
 | 
	
		
			
				|  |  | +                            {
 | 
	
		
			
				|  |  | +                                temp = x;
 | 
	
		
			
				|  |  | +                            }
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                        else
 | 
	
		
			
				|  |  | +                        {
 | 
	
		
			
				|  |  | +                            if (temp != 0)
 | 
	
		
			
				|  |  | +                            {
 | 
	
		
			
				|  |  | +                                pathList.Add(new RectangularPolygon(temp, y, x - temp, 1));
 | 
	
		
			
				|  |  | +                                temp = 0;
 | 
	
		
			
				|  |  | +                            }
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                }
 | 
	
		
			
				|  |  | +            });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return new ComplexPolygon(new PathCollection(pathList));
 | 
	
		
			
				|  |  | +        }
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |          /// <summary>
 | 
	
		
			
				|  |  |          /// 获得验证数据
 | 
	
		
			
				|  |  |          /// </summary>
 | 
	
	
		
			
				|  | @@ -372,53 +163,60 @@ namespace ZhonTai.Admin.Tools.Captcha
 | 
	
		
			
				|  |  |              //var client = new HttpClient();
 | 
	
		
			
				|  |  |              //var stream = await client.GetStreamAsync("https://picsum.photos/310/155");
 | 
	
		
			
				|  |  |              //client.Dispose();
 | 
	
		
			
				|  |  | -            //Bitmap baseImage = new Bitmap(stream);
 | 
	
		
			
				|  |  | -            //stream.Dispose();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            var oriImage = Image.FromFile($@"{Directory.GetCurrentDirectory()}\wwwroot\captcha\jigsaw\{new Random().Next(1, 4)}.jpg".ToPath());
 | 
	
		
			
				|  |  | -            //更改图片尺寸
 | 
	
		
			
				|  |  | -            //Bitmap baseImage = ResizeImage(oriImage, 310, 155);
 | 
	
		
			
				|  |  | -            Bitmap baseImage = new Bitmap(oriImage);
 | 
	
		
			
				|  |  | -            oriImage.Dispose();
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            var oriTemplate = Image.FromFile($@"{Directory.GetCurrentDirectory()}\wwwroot\captcha\jigsaw\templates\{new Random().Next(1, 7)}.png".ToPath());
 | 
	
		
			
				|  |  | -            Bitmap templateImage = new Bitmap(oriTemplate);
 | 
	
		
			
				|  |  | -            oriTemplate.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());
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              int baseWidth = baseImage.Width;
 | 
	
		
			
				|  |  |              int baseHeight = baseImage.Height;
 | 
	
		
			
				|  |  |              int templateWidth = templateImage.Width;
 | 
	
		
			
				|  |  |              int templateHeight = templateImage.Height;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +            //拼图
 | 
	
		
			
				|  |  | +            using var blockImage = new Image<Rgba32>(templateWidth, templateHeight);
 | 
	
		
			
				|  |  | +            //滑块拼图
 | 
	
		
			
				|  |  | +            using var sliderBlockImage = new Image<Rgba32>(templateWidth, baseHeight);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  |              //随机生成拼图坐标
 | 
	
		
			
				|  |  | -            PointModel point = GeneratePoint(baseWidth, baseHeight, templateWidth, templateHeight);
 | 
	
		
			
				|  |  | -            int x = point.X;
 | 
	
		
			
				|  |  | -            int y = point.Y;
 | 
	
		
			
				|  |  | +            PointModel blockPoint = GeneratePoint(baseWidth, baseHeight, templateWidth, templateHeight);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | +            //根据模板图计算轮廓
 | 
	
		
			
				|  |  | +            var blockShape = CalcBlockShape(templateImage);
 | 
	
		
			
				|  |  |              //生成拼图
 | 
	
		
			
				|  |  | -            string blockImageBase64 = "data:image/png;base64," + ImgToBase64String(CutByTemplate(baseImage, templateImage, x, y));
 | 
	
		
			
				|  |  | +            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));
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            //生成滑块拼图
 | 
	
		
			
				|  |  | +            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));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            //生成干扰图
 | 
	
		
			
				|  |  | -            PointModel interferencePoint = GenerateInterferencePoint(baseWidth, baseHeight, templateWidth, templateHeight, x, y);
 | 
	
		
			
				|  |  | -            InterferenceByTemplate(baseImage, templateImage, interferencePoint.X, interferencePoint.Y);
 | 
	
		
			
				|  |  | +            //生成干扰图坐标
 | 
	
		
			
				|  |  | +            PointModel interferencePoint = GenerateInterferencePoint(baseWidth, baseHeight, templateWidth, templateHeight, blockPoint.X, blockPoint.Y);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            string baseImageBase64 = "data:image/png;base64," + ImgToBase64String(baseImage);
 | 
	
		
			
				|  |  | -            templateImage.Dispose();
 | 
	
		
			
				|  |  | -            baseImage.Dispose();
 | 
	
		
			
				|  |  | +            //生成干扰图底图
 | 
	
		
			
				|  |  | +            baseImage.Mutate(x => x.DrawImage(templateImage, new Point(interferencePoint.X, interferencePoint.Y), (float)0.5));
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              var token = Guid.NewGuid().ToString();
 | 
	
		
			
				|  |  | -            CaptchaOutput captchaData = new CaptchaOutput
 | 
	
		
			
				|  |  | +            var captchaData = new CaptchaOutput
 | 
	
		
			
				|  |  |              {
 | 
	
		
			
				|  |  |                  Token = token,
 | 
	
		
			
				|  |  |                  Data = new SlideJigsawCaptchaDto()
 | 
	
		
			
				|  |  |                  {
 | 
	
		
			
				|  |  | -                    BlockImage = blockImageBase64,
 | 
	
		
			
				|  |  | -                    BaseImage = baseImageBase64
 | 
	
		
			
				|  |  | +                    BaseImage = baseImage.ToBase64String(PngFormat.Instance),
 | 
	
		
			
				|  |  | +                    BlockImage = sliderBlockImage.ToBase64String(PngFormat.Instance)
 | 
	
		
			
				|  |  |                  }
 | 
	
		
			
				|  |  |              };
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              var key = string.Format(captchaKey, token);
 | 
	
		
			
				|  |  | -            await _cache.SetAsync(key, point.X);
 | 
	
		
			
				|  |  | +            await _cache.SetAsync(key, blockPoint.X);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              return captchaData;
 | 
	
		
			
				|  |  |          }
 |