.Net 6 は回転検証コードを実装します

以前の記事では、.Net 6 によって実装されたスライド認証コード機能を紹介しました。最近、スライド認証コードはスライド認証コードにImageSharp置き換えられSkiaSharp、切り抜き部分は pojianbing のコードを指します。確認コードをスライドさせた後、私は考えました。回転キャプチャを作成します。実際、ローテーション認証コードはスライド認証コードに似ています。

最初にレンダリングを見てみましょう:
ここに画像の説明を挿入
回転の実装原理は、スライド検証コードの原理と同じです:

  • 1.背景画像を取得する
  • 2. テンプレートのグルーブマップとスライダーマップを取得する
  • 3. 溝切りを行う
  • 4.キャンバスを回転する
  • 5. スライダー マップへのマッピング
  • 6.背景画像にグルーヴマップのテンプレートを重ねる

キャプチャ エンティティ クラス ImageCaptchaInfo

public class ImageCaptchaInfo
{
    
    
    /// <summary>
    /// 背景图宽
    /// </summary>
    public int BackgroundImageWidth {
    
     get; set; }
    /// <summary>
    /// 背景图高
    /// </summary>
    public int BackgroundImageHeight {
    
     get; set; }
    /// <summary>
    /// 背景图
    /// </summary>
    public string BackgroundImageBase64 {
    
     get; set; }
    /// <summary>
    /// 滑动块图宽
    /// </summary>
    public int SliderImageWidth {
    
     get; set; }
    /// <summary>
    /// 滑动块图高
    /// </summary>
    public int SliderImageHeight {
    
     get; set; }
    /// <summary>
    /// 滑动块图
    /// </summary>
    public string SliderImageBase64 {
    
     get; set; }

    /// <summary>
    /// 随机值
    /// </summary>
    public int RandomX {
    
     get; set; }

    /// <summary>
    /// 容错值,可以为空!
    /// </summary>
    public float Tolerant {
    
     get; set; }
    /// <summary>
    /// 验证码类型
    /// </summary>
    public string CaptchaType {
    
     get; set; }

    public float Percentage
    {
    
    
        get
        {
    
    
            if (BackgroundImageWidth <= 0) return 0;
            return 1.0F * RandomX / BackgroundImageWidth;
        }
    }
}

その中で、ランダム値は、スライド率の計算RandomX に参加することです。役割については後述します。PercentagePercentage

ローテーション キャプチャ エンティティを定義します RotateImageCaptchaInfo

public class RotateImageCaptchaInfo : ImageCaptchaInfo
{
    
    
    /// <summary>
    /// 旋转多少度
    /// </summary>
    public float Degree {
    
     get; set; }


    public void Check()
    {
    
    
        //校验
        if (this.Degree <= 0) throw new TaCaptchaException($"RotateImageCaptchaInfo数据异常: {
      
      nameof(Degree)}小于等于0");
        if (this.RandomX <= 0) throw new TaCaptchaException($"RotateImageCaptchaInfo数据异常: {
      
      nameof(RandomX)}小于等于0");
        if (this.BackgroundImageWidth <= 0) throw new TaCaptchaException($"RotateImageCaptchaInfo数据异常: {
      
      nameof(BackgroundImageWidth)}小于等于0");
        if (this.BackgroundImageHeight <= 0) throw new TaCaptchaException($"RotateImageCaptchaInfo数据异常: {
      
      nameof(BackgroundImageHeight)}小于等于0");
        if (this.SliderImageWidth <= 0) throw new TaCaptchaException($"RotateImageCaptchaInfo数据异常: {
      
      nameof(SliderImageWidth)}小于等于0");
        if (this.SliderImageHeight <= 0) throw new TaCaptchaException($"RotateImageCaptchaInfo数据异常: {
      
      nameof(SliderImageHeight)}小于等于0");
        if (string.IsNullOrWhiteSpace(this.BackgroundImageBase64)) throw new TaCaptchaException($"RotateImageCaptchaInfo数据异常: {
      
      nameof(BackgroundImageBase64)}为空");
        if (string.IsNullOrWhiteSpace(this.SliderImageBase64)) throw new TaCaptchaException($"RotateImageCaptchaInfo数据异常: {
      
      nameof(SliderImageBase64)}为空");
    }
}

Check検証方法では、回転度Degreeやランダム値RandomXなどが条件を満たさない場合、自動的にエラーを返します。

インターフェイス IRotateCaptchaImageGenerator を定義する

ローテーション検証コード インターフェイスを定義します。これは比較的単純で、検証コードを生成するためのメソッドです。

public interface IRotateCaptchaImageGenerator
{
    
    
	Task<RotateImageCaptchaInfo> Generate(string captchaId);
}

確認コードを生成する

public class RotateCaptchaImageGenerator : IRotateCaptchaImageGenerator
{
    
    
    private readonly IResourceManager _resourceManager;
    private readonly Random _random = new Random();
      
    public RotateCaptchaImageGenerator(IResourceManager resourceManager)
    {
    
    
        _resourceManager = resourceManager;
            
    }

    public async Task<RotateImageCaptchaInfo> Generate(string captchaId)
    {
    
    

        //获取背景图
        var background = await _resourceManager.RandomBackground();
        //获取滑块图、凹槽图
        (var slider, var notch) = await _resourceManager.RandomTemplate(CaptchaTypeConstant.ROTATE);

        using var backgroundImage = SKBitmap.Decode(background);
        //滑块
        using var sliderTemplateImage = SKBitmap.Decode(slider);
        //凹槽
        using var notchTemplateImage = SKBitmap.Decode(notch);

        //定义空的凹槽图与滑块图
        using var notchMattingImage = new SKBitmap(notchTemplateImage.Width, notchTemplateImage.Height);
        using var sliderBarImage = new SKBitmap(360,360);


        //根据透明度计算凹槽图轮廓形状(形状由不透明区域形成)
        var notchShape = CaptchaImageUtils.GetImageShape(notchTemplateImage);

        //滑块图画布
        using var sliderCanvas = new SKCanvas(notchMattingImage);
        //叠加轮廓图
        sliderCanvas.ClipPath(notchShape, SKClipOperation.Intersect, true);
        //计算居中的位置
        int x = backgroundImage.Width / 2 - notchTemplateImage.Width / 2;
        int y = backgroundImage.Height / 2 - notchTemplateImage.Height / 2;
        //随机旋转抠图部分

        int randomX = _random.Next(notchTemplateImage.Width + 10, backgroundImage.Width - 10);
        float degree = 360f - randomX / (backgroundImage.Width / 360f);
        sliderCanvas.RotateDegrees(degree, notchMattingImage.Width/2, notchMattingImage.Height/2);

        //绘制抠图
        sliderCanvas.DrawBitmap(backgroundImage,-x,-y);
        //叠加滑块模板
        sliderCanvas.DrawBitmap(sliderTemplateImage, 0, 0);
            

        int bw = 360;
        int bh = 360;
        int cw = notchMattingImage.Width;
        int ch = notchMattingImage.Height;
        int iw = (int)(bw / 2 - cw / 2);
        int ih = (int)(bh / 2 - ch / 2);

        using var sliderBarCanvas = new SKCanvas(sliderBarImage);
        sliderBarCanvas.DrawBitmap(notchMattingImage, iw, ih);
           


           

        using var backgroundCanvas = new SKCanvas(backgroundImage);
        //叠加凹槽
        backgroundCanvas.DrawBitmap(notchTemplateImage, x, y);

        return new RotateImageCaptchaInfo
        {
    
    
            BackgroundImageWidth = backgroundImage.Width,
            BackgroundImageHeight = backgroundImage.Height,
            BackgroundImageBase64 = backgroundImage.ToBase64String(SKEncodedImageFormat.Png),
            RandomX = randomX,
            Degree = degree,
            Tolerant = 0.03f,
            SliderImageWidth = notchMattingImage.Width,
            SliderImageHeight = notchMattingImage.Height,
            SliderImageBase64 = sliderBarImage.ToBase64String(SKEncodedImageFormat.Png),
            CaptchaType = CaptchaTypeConstant.ROTATE
        };

    }
}

コードでは、最初に背景画像、溝画像、スライダー画像を取得し、それらを に変換しますSKBitmap

空の溝とスライダー プロットを定義します。グルーブ マップに従って、グルーブ マップのパスを取得します。

溝のカットアウトを取得

/// <summary>
/// 获取图形轮廓,形状由不透明的区域形成
/// </summary>
/// <param name="image">要获取轮廓的图片</param>
/// <returns></returns>
public static SKPath GetImageShape(SKBitmap image)
{
    
    
    int temp = 0;
    var path = new SKPath();
    for(int y=0;y< image.Height;y++)
    {
    
    
        for(int x=0;x< image.Width;x++)
        {
    
    
            var pixel = image.GetPixel(x, y);
            if(pixel.Alpha!=0)
            {
    
    
                if(temp==0)
                {
    
    
                    temp = x;
                }
            }
            else
            {
    
    
                if(temp!=0)
                {
    
    
                    path.AddRect(new SKRect(temp, y, x, y + 1));
                    temp= 0;
                }
            }
        }
    }
    return path;
}

メソッドでパスを定義しpath各ブロックのピクセル情報を列ごとに取得し、メソッドを使用して を取得します属性は5つSKBitmap GetPixelSKColorSKColor

  • アルファ
  • フエ
  • その中で
    、判定がAlpha0ではない、つまり透けていないと判断すればいいだけです。

SKCanvas溝のカットアウトを取得したら、キャンバスと呼ぶものを定義する必要があります。名前は ですsliderCanvassliderCanvas背景の切り抜きを上に描画する必要があります。
使用方法は、ClipPath最初にsliderCanvasコンター マップnotchShape、つまり生成したばかりの溝マットを重ね合わせます。ClipPathメソッドには複数のオーバーロードがあり、ここで使用されるパラメーターは 、SKPathおよびSKClipOperationですantialias
最初のパラメーターは取得したばかりの輪郭画像notchShape、2 番目のパラメーターはSKClipOperation.Intersect2 つの領域の交点を取得するように選択され、3 番目のパラメーターは true に設定されます。これはアンチエイリアシングを意味します。
等高線図を重ね合わせたら、まず背景図上で差し引く位置を計算します。まず背景画像の中心位置を取得し、溝画像の中心位置を差し引きます。得られた x と y の値は、描画する始点の座標です。
次に、ランダム値に従って、RotateDegreesメソッドを使用してキャンバスをランダムに回転させます。RotateDegreesメソッドの最初のパラメーターは回転の角度で、2 番目と 3 番目のパラメーターは回転の中心点を決定します。
背景の切り抜き部分をキャンバスに描画し、スライダーマップのテンプレートをキャンバスに描画するように書かれています。
次に、スライダーのキャンバスを定義しますsliderBarCanvasスライダーに作った切り抜きを描きます。
最後に、バックグラウンド マップにグルーブ マップを描画します。
すべてが描画されたら、情報をフロントエンドに返します。それだけです。コードで返される base64 文字列は、私が自分で作成したSKBitmap拡張機能であり、非常に単純です。

public static string ToBase64String(this SKBitmap source, SKEncodedImageFormat format)
{
    
    
    using var img = SKImage.FromBitmap(source);
    using SKData data = img.Encode(format, 100);
    var array = data.ToArray();
    return "data:" + format.ToString().ToLower() + ";base64," + Convert.ToBase64String(array, 0, array.Length);
}

ここのところ。キャプチャを回転させるためのコードはすべて完了です。

フロントエンドコード

先ほどのスライド検証コードと同様に、修正が必要な箇所は非常に少ないですが、resetメソッドではスライダーの位置を中心点の位置に設定し、回転を0に設定します

$(".captcha_slider").css('left', (captchaMainWidth - captchaMainHeight)/2);
$(".captcha_slider").css("transform", "rotate(0deg)")

handleDragMovingメソッドでは、スライダーを左から右に移動する代わりに選択済みに設定します

$('#sliderSrc').css('transform',"rotate("+(_x/(206/360))+"deg)");

その他は変更ありません。フロントエンドコードはこちらの記事で詳しく紹介しています
. NET 6で実現するスライド検証コード (10), フィナーレ: フロントエンドコードの戦闘, vue3とHTML+JQuery

要約する

クリック検証コード、グラフィック検証コードなど、他の種類の検証コードがあります。それは徐々に完成され、実現されます。

下の公式アカウントカードをクリックしてフォローしてください!一緒に学び、一緒に進歩しましょう!

おすすめ

転載: blog.csdn.net/sd2208464/article/details/128507887