C#实现旋转图片验证码

开发环境:C#,VS2019,.NET Core 3.1,ASP.NET Core

1、建立一个验证码控制器

新建两个方法Create和Check,Create用于创建验证码(返回1张图片和令牌),Check用于验证(验证图片旋转角度)它是否有效。

声明一个静态类变量存放列表,列表中存放包含令牌和验证码的对象。

        /// <summary>
        /// 返回一张图片和令牌.
        /// </summary>
        /// <returns></returns>
        public string Create()
        {
            try
            {
                // 记录验证码到缓存中
                VCodeCircleModel model = new VCodeCircleModel();
                model.id = Guid.NewGuid().ToString();    // 生成令牌
                var vcode = VCodeCircleModel.GetVCode();    // 生成验证码
                model.code = vcode;
                _list.Add(model);

                // 返回图片
                var images = VCodeCircleModel.GetImage(Convert.ToInt32(vcode));
                VCodeCircleController_Create_Receive result = new VCodeCircleController_Create_Receive();
                result.code = "0";
                result.data.id = model.id;
                result.data.img = VCodeCircleModel.BitmapToBase64Str(images);
                var json = JsonConvert.SerializeObject(result);
                return json;
            }
            catch (Exception ex)
            {
                _logger.LogWarning(exception: ex, message: ex.Message);
                VCodeCircleController_Create_Receive result = new VCodeCircleController_Create_Receive();
                result.code = "999999";
                result.msg = "系统异常";
                var json = JsonConvert.SerializeObject(result);
                return json;
            }
        }


        public string Check(string id, string code)
        {
            try
            {
                // 旋转图片的误差在±5
                var temp = Convert.ToInt32(code) - 5;
                var index = _list.FindIndex(m =>
                {
                    if (m.id.Equals(id))
                    {
                        for (int i = 0; i < 10; i++)
                        {
                            if (m.code.Equals(temp.ToString()))
                            {
                                return true;
                            }

                            temp++;
                        }
                    }

                    return false;
                });

                ReceiveObject result = new ReceiveObject();
                if (index >= 0)
                {
                    _list.RemoveAt(index);
                    result.code = "0";
                    result.msg = "验证成功";
                    var json = JsonConvert.SerializeObject(result);
                    return json;
                }
                else
                {
                    result.code = "1";
                    result.msg = "验证失败";
                    var json = JsonConvert.SerializeObject(result);
                    return json;
                }
            }
            catch (Exception ex)
            {
                _logger.LogError(exception: ex, message: ex.Message);
                ReceiveObject result = new ReceiveObject();
                result.code = "999999";
                result.msg = "系统异常";
                var json = JsonConvert.SerializeObject(result);
                return json;
            }
        }

    public class VCodeCircleModel
    {
        /// <summary>
        /// 令牌.
        /// </summary>
        public string id { get; set; }

        /// <summary>
        ///验证码.
        /// </summary>
        public string code { get; set; }

        /// <summary>
        /// 获取随机验证码.
        /// </summary>
        /// <returns></returns>
        public static string GetVCode()
        {
            // 这里的随机码是旋转图片的角度,至少旋转60度,最多旋转300度
            Random random = new Random();
            return random.Next(60, 300).ToString();
        }

        /// <summary>
        /// 随机获取一张图片.
        /// </summary>
        /// <returns></returns>
        public static Bitmap GetImage(int angle)
        {
            // 从文件加载原图
            Random random = new Random();
            var image_index = random.Next(0, 2);
            Image originImage;
            switch (image_index)
            {
                case 0:
                    originImage = Image.FromFile(string.Format(@"{0}\Images\{1}", PathHelper.Path, "circleImg1.png"));
                    break;

                case 1:
                default:
                    originImage = Image.FromFile(string.Format(@"{0}\Images\{1}", PathHelper.Path, "circleImg2.png"));
                    break;
            }

            originImage = Rotate(originImage as Bitmap, angle);
            return (Bitmap)originImage;
        }

        /// <summary>
        /// 图片旋转
        /// </summary>
        /// <param name="ImageOriginal">原图.</param>
        /// <param name="AngleValue">旋转角度.</param>
        /// <returns></returns>
        public static Bitmap Rotate(Bitmap ImageOriginal, float AngleValue)
        {
            AngleValue = AngleValue % 360;
            double radian = AngleValue * Math.PI / 180.0;
            double cos = Math.Cos(radian);
            double sin = Math.Sin(radian);
            int w = ImageOriginal.Width;
            int h = ImageOriginal.Height;
            int W = (int)(Math.Max(Math.Abs(w * cos - h * sin), Math.Abs(w * cos + h * sin)));
            int H = (int)(Math.Max(Math.Abs(w * sin - h * cos), Math.Abs(w * sin + h * cos)));
            Bitmap ImageBaseOriginal = new Bitmap(W, H, PixelFormat.Format32bppArgb);
            System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(ImageBaseOriginal);
            g.InterpolationMode = InterpolationMode.NearestNeighbor;
            g.SmoothingMode = SmoothingMode.HighQuality;
            Point Offset = new Point((W - w) / 2, (H - h) / 2);
            Rectangle rect = new Rectangle(Offset.X, Offset.Y, w, h);
            Point center = new Point(rect.X + rect.Width / 2, rect.Y + rect.Height / 2);
            g.Clear(Color.White);
            g.TranslateTransform(center.X, center.Y);
            g.RotateTransform(360 - AngleValue);
            g.TranslateTransform(-center.X, -center.Y);
            g.DrawImage(ImageOriginal, rect);
            g.ResetTransform();
            g.Save();
            g.Dispose();
            return ImageBaseOriginal;
        }

        /// <summary>
        /// 将图片对象转成Base64的字符串.
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        public static string BitmapToBase64Str(Bitmap bitmap)
        {
            using (MemoryStream memoryStream = new MemoryStream())
            {
                bitmap.Save(memoryStream, ImageFormat.Jpeg);
                byte[] bytes = memoryStream.ToArray();
                return Convert.ToBase64String(memoryStream.ToArray());
            }
        }
    }

2、新建一个视图文件,引入jquery,css文件,js方法中添加三个鼠标事件 - 鼠标按下,鼠标移动和鼠标松开。页面首次加载时调用控制器的Create方法获取图片和令牌,在鼠标松开时调用Check方法验证旋转的角度是否有效。

本来想实现鼠标在图片上拖动后让图片的效果,但发现难度有点大,就换成了拖动滑块后让图片旋转的形式。

<link href="~/css/circle_slide.css" rel="stylesheet" type="text/css" />

<!-- 展示验证码 -->
<div class="container">
    <div class="main">
        <div id="content" class="content">
            <img id="backImage" src="" alt="">
        </div>
    </div>
    <div id="slider">
        <div id="sliderBlock"></div>
    </div>
</div>

<script src="~/lib/jquery/dist/jquery.js"></script>
<script src="~/js/MyCircleSlide.js"></script>

* {
    margin: 0;
    padding: 0;
}

.main {
    position: relative;
    margin-left: 20px;
    margin-top: 20px;
    width: 200px;
    background-color: white;
}

.content {
    width: 100%;
}

    .content img {
        width: 100%;
        height: auto;
    }


#slider {
    width: 85%;
    height: 40px;
    background-color: aliceblue;
    position: relative;
}

#sliderBlock {
    position: absolute;
    left: 5px;
    height: 30px;
    width: 45px;
    top: 5px;
    background-color: white;
    border-radius: 5px;
    box-shadow: 0 0 10px 2px lightgray;
}

$(function () {
    var _imageBase64;    // 大图
    var _id;

    // 鼠标左键是否按下
    var isMouseDown;

    // 鼠标按下x值
    var mouseDownStartX;

    // 鼠标移动距离
    var mouseMoveLength;

    init();

    document.onmousedown = function (event) {
        var obj = getElementPosition(document.getElementById('sliderBlock'))
        if (event.clientX > obj.left &&
            event.clientX < (obj.left + obj.width) &&
            event.clientY > obj.top &&
            event.clientY < (obj.top + obj.height)) {
            // 鼠标点击事件发生在滑动条的范围内
            this.isMouseDown = true
            this.mouseDownStartX = event.clientX
            console.log("鼠标点击事件发生在滑动条的范围内");
        }
    }

    document.onmousemove = function (event) {
        if (this.isMouseDown) {
            this.mouseMoveLength = event.clientX - this.mouseDownStartX;    // 计算滑块拖动的距离
            if (this.mouseMoveLength > 0 &&
                this.mouseMoveLength < 360) {
                // 滑块拖动的最小距离是5px,最大距离是大图的宽度 - 小图的宽度
                document.getElementById('sliderBlock').style.left = 5 + this.mouseMoveLength + 'px'
                $("#backImage").css("transform", "rotate(" + (this.mouseMoveLength) + "deg)");
            }
        }
    }

    document.onmouseup = function (event) {
        // 鼠标松开后停止拖动
        if (this.isMouseDown) {
            this.isMouseDown = false
            // console.log("小图移动了:" + this.mouseMoveLength);
            // check(x.replace("px", ""));
            check(this.mouseMoveLength);
        }
    }

    // dom在浏览器的位置
    function getElementPosition(element) {
        let top = element.offsetTop
        let left = element.offsetLeft
        let width = element.offsetWidth
        let height = element.offsetHeight
        var currentParent = element.offsetParent;
        while (currentParent !== null) {
            top += currentParent.offsetTop
            left += currentParent.offsetLeft
            currentParent = currentParent.offsetParent
        }

        return { top, left, width, height }
    }

    function check(x) {
        $.get("Check?code=" + x + "&id=" + _id, function (data) {
            var obj = JSON.parse(data);
            if (obj.code == "0") {
                alert("验证成功");
            }
            else {
                alert("验证失败");
            }
        });
    }

    // 设置当前图片
    function setCurrentImageBase64(imageBase64) {
        _imageBase64 = imageBase64
        document.getElementById('backImage').src = _imageBase64
    }

    function init() {
        $.get("Create", function (data) {
            // 获取两张图片和令牌
            var obj = JSON.parse(data);
            _id = obj.data.id;
            setCurrentImageBase64('data:image/webp;base64,' + obj.data.img);
        });
    }
});

效果图:

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/64448.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

决策树和随机森林对比

1.用accuracy来对比 # -*-coding:utf-8-*-""" accuracy来对比决策树和随机森林 """ from sklearn.tree import DecisionTreeClassifier from sklearn.ensemble import RandomForestClassifier from sklearn.datasets import load_wine#(178, 13…

【LeetCode】240.搜索二维矩阵Ⅱ

题目 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。每列的元素从上到下升序排列。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,4,7,11,15],[2,5,8,12,19],[3,6,9,16,22],[10,13,…

Iotdb 0.13配置集群和数据同步共享

描述 官网集群配置示例&#xff1a;官方文档 准备2台服务器&#xff0c;并且相互可以ping通和相关端口开放&#xff1a; 192.168.1.1192.168.1.2 相关介绍请查看官网及相关文档。 配置 1、iotdb 0.13版本下载&#xff08;如果已安装请跳过&#xff09;&#xff0c;进入op…

24届近5年杭州电子科技大学自动化考研院校分析

今天给大家带来的是杭州电子科技大学控制考研分析 满满干货&#xff5e;还不快快点赞收藏 一、杭州电子科技大学 学校简介 杭州电子科技大学&#xff08;Hangzhou Dianzi University&#xff09;&#xff0c;简称“杭电”&#xff0c;位于杭州市&#xff0c;是浙江省人民政…

PE半透明屏,在建筑行业中,有哪些应用展示?

PE半透明屏是一种新型的屏幕材料&#xff0c;具有半透明的特点。 它由聚乙烯&#xff08;PE&#xff09;材料制成&#xff0c;具有良好的透明度和柔韧性。 PE半透明屏广泛应用于建筑、广告、展览等领域&#xff0c;具有很高的市场潜力。 PE半透明屏的特点之一是其半透明性。…

弘扬“两弹一星”精神,勇攀科学技术高峰——道本科技商业大学党日活动圆满落幕

2023年8月2日&#xff0c;道本科技与商业大学携手举办了一场主题为“弘扬‘两弹一星’精神&#xff0c;勇攀科学技术高峰”的党日活动。本次活动旨在了解党领导下的中国核工业发展历程&#xff0c;传承和弘扬“两弹一星”精神&#xff0c;同时展示道本科技创新产品&#xff0c;…

【数据结构】单链表OJ题

&#x1f525;博客主页&#xff1a;小王又困了 &#x1f4da;系列专栏&#xff1a;数据结构 &#x1f31f;人之为学&#xff0c;不日近则日退 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、移除链表元素 &#x1f4a1;方法一&#xff1a; &#x1f4a1;方法二…

Netty: 向ChannelPipeline中添加ChannelHandler的顺序

Netty中的ChannelHandler有inbound handler&#xff0c;处理接收数据的过程&#xff1b;有outbound handler&#xff0c;处理发数据的过程。当然&#xff0c;也有的handler既处理接收的数据 &#xff0c;也处理发送的数据。 每个channel对应一个ChannelPipeline。handler被添加…

echarts绘制甘特图

说在前面 项目上有需求&#xff0c;需要在大屏上展示进度甘特图&#xff0c;调研了DHTMLX和普加甘特图&#xff0c;效果都不是特别符合需求现状&#xff0c;查询了一些博客&#xff0c;决定使用echarts来绘制甘特图。 实现效果展示 实现思路分析 1、应该采用柱状图&#xff…

mysql--InnoDB存储引擎--架构和事务

MySQL进阶篇 文章目录 架构1、逻辑结构InnoDB 逻辑存储单元主层级关系图&#xff1a;1、表空间2、段3、区4、页5、行总结&#xff1a; 2、架构2、1 内存架构2、2 磁盘架构 3、事务3、1事务基础&#xff08;1&#xff09;事务&#xff08;2&#xff09;特性 架构 1、逻辑结构 I…

嵌入式Linux驱动开发系列五:Linux系统和HelloWorld

三个问题 了解Hello World程序的执行过程有什么用? 编译和执行&#xff1a;Hello World程序的执行分为两个主要步骤&#xff1a;编译和执行。编译器将源代码转换为可执行文件&#xff0c;然后计算机执行该文件并输出相应的结果。了解这个过程可以帮助我们理解如何将代码转化…

D455+VINS-Fusion+surfelmapping 稠密建图(三)

继续&#xff0c;由surfelmapping建立的点云生成octomap八叉树栅格地图 一、安装OctomapServer 建图包 安装插件 sudo apt-get install ros-melodic-octomap-ros sudo apt-get install ros-melodic-octomap-msgs sudo apt-get install ros-melodic-octomap-server sudo apt-…

IT 基础架构自动化

什么是 IT 基础架构自动化 IT 基础架构自动化是通过使用技术来控制和管理构成 IT 基础架构的软件、硬件、存储和其他网络组件来减少人为干预的过程&#xff0c;目标是构建高效、可靠的 IT 环境。 为什么要自动化 IT 基础架构 为客户和员工提供无缝的数字体验已成为企业的当务…

mybtis-plus分页查询

文章目录 2.2 代码开发2.2.1 设计DTO类2.2.2 封装PageResult2.2.3 Controller层2.2.4 Service层接口2.2.5 Service层实现类2.2.6 Mapper层 3.3 代码实现3.3.1 分页插件配置3.3.2 分页查询实现 2.2 代码开发 2.2.1 设计DTO类 根据请求参数进行封装&#xff0c;在sky-pojo模块中…

SpringCloud整体架构概览

什么是SpringCloud 目标 协调任何服务&#xff0c;简化分布式系统开发。 简介 构建分布式系统不应该是复杂的&#xff0c;SpringCloud对常见的分布式系统模式提供了简单易用的编程模型&#xff0c;帮助开发者构建弹性、可靠、协调的应用程序。SpringCloud是在SpringBoot的基…

蓝牙资讯|苹果AirPods耳机新专利曝光,类似项链圈和钥匙圈

根据美国商标和专利局&#xff08;USPTO&#xff09;公示的清单&#xff0c;苹果近日获得了 AirPods 耳机相关的设计专利&#xff0c;在不使用时可以放置到“项链”和“钥匙圈”内&#xff0c;方便用户携带。 苹果在专利中表示&#xff0c;便携式电子设备虽然可以放到口袋或者…

Linux网络服务之部署yum仓库

yum &#xff1f; yum ! 一、YUM概述1.1 yum简介1.2 yum工作原理 二、yum 配置文件2.1 yum主配置文件2.2 yum仓库设置文件2.2.1 配置文件主要格式2.2.2 软件仓库的提供方式2.2.3 日志文件 三、yum命令详解3.1 安装和升级3.2 查询3.2.1 显示可用的安装包 ----- yum list3.2.2 显…

ChatGPT实战:创业咨询,少走弯路,少踩坑

用九死一生形容创业再适合不过&#xff0c;不过一旦成功回报也很诱人&#xff0c;这也是为什么那么多人下场创业。纸上得来终觉浅&#xff0c;绝知此事要躬行&#xff0c;创过业的人都知道其中的心酸&#xff0c;而他们也建议你去创业&#xff0c;因为那真不是一般人能干的事。…

The ‘kotlin-android-extensions‘ Gradle plugin is no longer supported.

Android使用kotlin开发&#xff0c;运行报错 The kotlin-android-extensions Gradle plugin is no longer supported. Please use this migration guide (https://goo.gle/kotlin-android-extensions-deprecation) to start working with View Binding (https://developer.an…

python excel 操作

excel文件内容如下&#xff1a; 一、xlrd 读Excel 操作 1、打开Excel文件读取数据 filexlrd.open_workbook(filename)#文件名以及路径&#xff0c;如果路径或者文件名有中文给前面加一个 r 2、常用函数 &#xff08;1&#xff09;获取一个sheet工作表 table file.sheets(…