您当前的位置:首页 > 电脑百科 > 程序开发 > 编程百科

一步一步生成滑动验证码图片

时间:2022-04-15 09:41:33  来源:博客园  作者:可爱的雯雯子

图片

名称

尺寸

一步一步生成滑动验证码图片

 

bg.jpg

552 * 344

一步一步生成滑动验证码图片

 

hole.png

110 * 110

一步一步生成滑动验证码图片

 

slider.png

110 * 110

hole.png和slider.png为png是因为图片带有透明度。


 

合成目标

最终为前端生成两张图片:

图片

名称

尺寸

一步一步生成滑动验证码图片

 

out_bg.jpg

552 * 344

一步一步生成滑动验证码图片

 

out_slider.png

110 * 344

out_slider.png高度为344与背景图等高。

也可以打开滑动验证Demo页面,F12来观察图片。

一步一步生成滑动验证码图片

 


一步一步生成滑动验证码图片

 


 

实现

本机环境为.NET 6.0.300-preview.22204.3, 装有Vscode。

1.创建项目

创建console项目

mkdir SlideImageGenerator
cd SlideImageGenerator
dotnet new console

2.添加ImageSharp

dotnet add package SixLabors.ImageSharp
dotnet add package SixLabors.ImageSharp.Drawing --prerelease

3.vscode打开

code .
一步一步生成滑动验证码图片

 

4.引入图片

创建Images目录, 并放入bg.jpg,hole.png,slider.png

mkdir Images
一步一步生成滑动验证码图片

 

5.生成out_bg.jpg

out_bg.jpg生成比较简单,直接将hole.png"叠加"到bg.jpg。hole.png灰色区域是半透明的,因此能够隐约看到背景。开始!
清空Program.cs,引入命名空间

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Drawing.Processing;

生成随机坐标,代表绘制凹槽的起始位置:

// 生成随机坐标
int randomX = 100, randomY = 120;

加载图片

using var backgroundImage = Image.Load<Rgba32>("images/bg.jpg");
using var holeTemplateImage = Image.Load<Rgba32>("images/hole.png");
using var sliderTemplateImage = Image.Load<Rgba32>("images/slider.png");

"叠加"holeTemplateImage到backgroundImage。用ImageSharp来说就是以backgroundImage为底,从位置randomX,randomY开始绘制holeTemplateImage。

backgroundImage.Mutate(x => x.DrawImage(holeTemplateImage, new Point(randomX, randomY), 1));
backgroundImage.SaveAsJpegAsync("out_bg.jpg");

运行

dotnet run

运行后可以在目录看到out_bg.jpg

一步一步生成滑动验证码图片

 

全部代码:

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Drawing.Processing;

// 生成随机坐标
int randomX = 100, randomY = 120;

// 加载图片
using var backgroundImage = Image.Load<Rgba32>("images/bg.jpg");
using var holeTemplateImage = Image.Load<Rgba32>("images/hole.png");
using var sliderTemplateImage = Image.Load<Rgba32>("images/slider.png");

// "叠加"holeTemplateImage到backgroundImage
backgroundImage.Mutate(x => x.DrawImage(holeTemplateImage, new Point(randomX, randomY), 1));
backgroundImage.SaveAsJpegAsync("out_bg.jpg");

6.生成out_slider.png

out_slider.png生成需要三步:
a. 从背景图中扣出凹槽区域,形成holeMattingImage。
b. 将slider.png"叠加"到抠图holeMattingImage。
c. 将b生成的图形"叠加"到一个高为344,宽为110的透明区域,最终生成out_slider.
以下具体讲解:
a步骤我直接上代码,其实就一个裁剪操作:

// backgroundImage已做修改,这里重新加载背景
using var backgroundImage2 = Image.Load<Rgba32>("images/bg.jpg");
using var holeMattingImage = new Image<Rgba32>(sliderTemplateImage.Width, sliderTemplateImage.Height); // 110 * 110
// 根据透明度计算凹槽图轮廓形状(形状由不透明区域形成)
var holeShape = CalcHoleShape(holeTemplateImage);
// 生成凹槽抠图
holeMattingImage.Mutate(x =>
{
    // 可以这样理解:
    //   将holeShape想象成一幅110X110的图片
    //   p => p.DrawImage(backgroundImage2, new Point(-randomX, -randomY), 1)则表示
    //   从holeShape的-randomX, -randomY开始绘制backgroundImage2(相当于backgroundImage2左移randomX,上移randomY)
    //   然后将holeShape绘制结果叠加到holeMattingImage上
    x.Clip(holeShape, p => p.DrawImage(backgroundImage2, new Point(-randomX, -randomY), 1));
});
holeMattingImage.SaveAsJpegAsync("out_holeMatting.jpg");

裁剪注意传入的负坐标,注释是我个人的理解。凹槽的形状通过CalcHoleShape实现的,原理是一行行扫描图像,每行连续不透明区域(包含半透明)形成一个或多个n*1的矩形。最后将所有小矩形组合形成一个组合形状ComplexPolygon

Func<Image<Rgba32>, ComplexPolygon> CalcHoleShape = (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));
};

运行,形成out_holeMatting.jpg

dotnet run 
一步一步生成滑动验证码图片

 

b. 将slider.png"叠加"到抠图holeMattingImage,代码比较简单

// 叠加拖块模板
holeMattingImage.Mutate(x => x.DrawImage(sliderTemplateImage, new Point(0, 0), 1));
holeMattingImage.SaveAsJpegAsync("out_holeMatting2.jpg");

运行,形成out_holeMatting2.jpg

dotnet run 
一步一步生成滑动验证码图片

 

c. 将out_holeMatting2叠加到"叠加"到一个高为344,宽为110的透明区域

using var sliderBarImage = new Image<Rgba32>(sliderTemplateImage.Width, backgroundImage2.Height);
// 绘制拖块条
sliderBarImage.Mutate(x => x.DrawImage(holeMattingImage, new Point(0, randomY), 1));
sliderBarImage.SaveAsJpegAsync("out_slider.jpg");

运行,形成out_slider.jpg

dotnet run 
一步一步生成滑动验证码图片

 

全部代码

using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Drawing;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Drawing.Processing;

// 生成随机坐标
int randomX = 100, randomY = 120;

// 加载图片
using var backgroundImage = Image.Load<Rgba32>("images/bg.jpg");
using var holeTemplateImage = Image.Load<Rgba32>("images/hole.png");
using var sliderTemplateImage = Image.Load<Rgba32>("images/slider.png");

// "叠加"holeTemplateImage到backgroundImage
backgroundImage.Mutate(x => x.DrawImage(holeTemplateImage, new Point(randomX, randomY), 1));
backgroundImage.SaveAsJpegAsync("out_bg.jpg");

Func<Image<Rgba32>, ComplexPolygon> CalcHoleShape = (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));
};

// backgroundImage已做修改,这里重新加载背景
using var backgroundImage2 = Image.Load<Rgba32>("images/bg.jpg");
using var holeMattingImage = new Image<Rgba32>(sliderTemplateImage.Width, sliderTemplateImage.Height); // 110 * 110
// 根据透明度计算凹槽图轮廓形状(形状由不透明区域形成)
var holeShape = CalcHoleShape(holeTemplateImage);
// 生成凹槽抠图
holeMattingImage.Mutate(x =>
{
    // 可以这样理解:
    //   将holeShape想象成一幅110X110的图片
    //   p => p.DrawImage(backgroundImage2, new Point(-randomX, -randomY), 1)则表示
    //   从holeShape的-randomX, -randomY开始绘制backgroundImage2(相当于backgroundImage2左移randomX,上移randomY)
    //   然后将holeShape绘制结果叠加到holeMattingImage上
    x.Clip(holeShape, p => p.DrawImage(backgroundImage2, new Point(-randomX, -randomY), 1));
});
holeMattingImage.SaveAsJpegAsync("out_holeMatting.jpg");

// 叠加拖块模板
holeMattingImage.Mutate(x => x.DrawImage(sliderTemplateImage, new Point(0, 0), 1));
holeMattingImage.SaveAsJpegAsync("out_holeMatting2.jpg");

using var sliderBarImage = new Image<Rgba32>(sliderTemplateImage.Width, backgroundImage2.Height);
// 绘制拖块条
sliderBarImage.Mutate(x => x.DrawImage(holeMattingImage, new Point(0, randomY), 1));
sliderBarImage.SaveAsJpegAsync("out_slider.jpg");

最后

完整的滑动验证,可以参考LazySlideCaptcha。写的比较水,欢迎Star。

  • 本文作者: 破剑冰
  • 本文链接: https://www.cnblogs.com/readafterme/p/16110788.html


Tags:验证码   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,不构成投资建议。投资者据此操作,风险自担。如有任何标注错误或版权侵犯请与我们联系,我们将及时更正、删除。
▌相关推荐
注意!密码、验证码都没说,钱是怎么被骗走的?
转自:科普中国“我密码和验证码都没有给他,为什么钱还是被骗子骗走了?”骗子是怎么做到的呢?真实案例今年1月,武汉市民张某在家接到一陌生电话,电话自称是某平台的客服,告诉张某购...【详细内容】
2024-04-11  Search: 验证码  点击:(11)  评论:(0)  加入收藏
微软 Edge 浏览器将推出两大新功能:设备端加密和自动验证验证码
8 月 23 日消息,微软正在为其 Edge 浏览器开发新功能,将为用户带来更便捷的体验以及更好的隐私和安全保护。据 Leopeva64 发现,微软正在为 Edge 浏览器的安卓版本开发两个新功...【详细内容】
2023-08-23  Search: 验证码  点击:(295)  评论:(0)  加入收藏
在WordPress登录和注册表中添加验证码
您想将CAPTCHA添加到WordPress网站的登录和注册表单中吗?WordPress登录和用户注册页面通常是黑客,垃圾邮件发送者和暴力攻击的主要目标。避免这些攻击的一种方法是使用CAPTCHA...【详细内容】
2023-08-03  Search: 验证码  点击:(263)  评论:(0)  加入收藏
验证码越来越抽象,我快不能证明自己是人类了。
为了把机器人拦在门外,人类发明了验证码。但不知何时起,验证码开始处处刁难人类。它就像路上的减速带,你过是能过,但总会咯噔一下,而且越急就越难受。黑胖和我说,那夜他突想温习两...【详细内容】
2023-07-03  Search: 验证码  点击:(243)  评论:(0)  加入收藏
验证码竟成骚扰工具,谁在作祟?
本是用于APP注册、网站登录身份验证的手机短信验证码,摇身一变成了骚扰手机用户的帮凶,这是怎么回事儿?近期,不少市民到四川遂宁公安机关报案称:自己手机突然“抽风”,在非本人操...【详细内容】
2023-04-21  Search: 验证码  点击:(254)  评论:(0)  加入收藏
五分钟搞定验证码,你学会了吗?
哈喽,大家好,我是了不起。我们其实很经常看到,登录一些网站其实是需要验证码的。使用验证码是现在很多网站通行的一种方式,因为计算机很难识别验证码,所以可以识别验证码的用户就...【详细内容】
2023-04-04  Search: 验证码  点击:(173)  评论:(0)  加入收藏
KgCaptcha 行为验证码安全策略设置
前言在验证码项目中,都会遇到验证码被恶意大量高频的调用,给服务造成很多无效的注册或登录,占用大量的系统资源。而我在想,有没有哪一款验证码产品可以设置黑/白名单限制IP访问...【详细内容】
2023-03-03  Search: 验证码  点击:(135)  评论:(0)  加入收藏
Spring Security自定义认证逻辑实现图片验证码登录
前言相信大家在网上冲浪都遇到过登录时输入图片验证码的情况,既然我们已经学习了 Spring Security,也上手实现过几个案例,那不妨来研究一下如何实现这一功能。首先需要明确的是...【详细内容】
2022-12-12  Search: 验证码  点击:(257)  评论:(0)  加入收藏
一键去除网页BOM属性「解决乱码,头部空白,验证码不显示问题」
几个常出现的问题:1.网站打开空白2.页面头部出现多余的空白3.网站出现乱码,如“锘�”4.后台登录验证码不显示解决方案:1.选用专业的编辑器,例如notepad++,sublime,editplus这样不会...【详细内容】
2022-11-25  Search: 验证码  点击:(341)  评论:(0)  加入收藏
一个简单的设置,让手机自动填充验证码,省心省力
大家好,我们日常手机登录各种不同的软件APP,除了使用账号密码登录以外,还可以使用手机验证码登录现在很多平台为了安全性,在我们输入密码登录的时候,额外还要求接受短信验证码进...【详细内容】
2022-11-22  Search: 验证码  点击:(220)  评论:(0)  加入收藏
▌简易百科推荐
Meta如何将缓存一致性提高到99.99999999%
介绍缓存是一种强大的技术,广泛应用于计算机系统的各个方面,从硬件缓存到操作系统、网络浏览器,尤其是后端开发。对于Meta这样的公司来说,缓存尤为重要,因为它有助于减少延迟、扩...【详细内容】
2024-04-15    dbaplus社群  Tags:Meta   点击:(1)  评论:(0)  加入收藏
SELECT COUNT(*) 会造成全表扫描?回去等通知吧
前言SELECT COUNT(*)会不会导致全表扫描引起慢查询呢?SELECT COUNT(*) FROM SomeTable网上有一种说法,针对无 where_clause 的 COUNT(*),MySQL 是有优化的,优化器会选择成本最小...【详细内容】
2024-04-11  dbaplus社群    Tags:SELECT   点击:(1)  评论:(0)  加入收藏
10年架构师感悟:从问题出发,而非技术
这些感悟并非来自于具体的技术实现,而是关于我在架构设计和实施过程中所体会到的一些软性经验和领悟。我希望通过这些分享,能够激发大家对于架构设计和技术实践的思考,帮助大家...【详细内容】
2024-04-11  dbaplus社群    Tags:架构师   点击:(2)  评论:(0)  加入收藏
Netflix 是如何管理 2.38 亿会员的
作者 | Surabhi Diwan译者 | 明知山策划 | TinaNetflix 高级软件工程师 Surabhi Diwan 在 2023 年旧金山 QCon 大会上发表了题为管理 Netflix 的 2.38 亿会员 的演讲。她在...【详细内容】
2024-04-08    InfoQ  Tags:Netflix   点击:(5)  评论:(0)  加入收藏
即将过时的 5 种软件开发技能!
作者 | Eran Yahav编译 | 言征出品 | 51CTO技术栈(微信号:blog51cto) 时至今日,AI编码工具已经进化到足够强大了吗?这未必好回答,但从2023 年 Stack Overflow 上的调查数据来看,44%...【详细内容】
2024-04-03    51CTO  Tags:软件开发   点击:(9)  评论:(0)  加入收藏
跳转链接代码怎么写?
在网页开发中,跳转链接是一项常见的功能。然而,对于非技术人员来说,编写跳转链接代码可能会显得有些困难。不用担心!我们可以借助外链平台来简化操作,即使没有编程经验,也能轻松实...【详细内容】
2024-03-27  蓝色天纪    Tags:跳转链接   点击:(16)  评论:(0)  加入收藏
中台亡了,问题到底出在哪里?
曾几何时,中台一度被当做“变革灵药”,嫁接在“前台作战单元”和“后台资源部门”之间,实现企业各业务线的“打通”和全域业务能力集成,提高开发和服务效率。但在中台如火如荼之...【详细内容】
2024-03-27  dbaplus社群    Tags:中台   点击:(13)  评论:(0)  加入收藏
员工写了个比删库更可怕的Bug!
想必大家都听说过删库跑路吧,我之前一直把它当一个段子来看。可万万没想到,就在昨天,我们公司的某位员工,竟然写了一个比删库更可怕的 Bug!给大家分享一下(不是公开处刑),希望朋友们...【详细内容】
2024-03-26  dbaplus社群    Tags:Bug   点击:(9)  评论:(0)  加入收藏
我们一起聊聊什么是正向代理和反向代理
从字面意思上看,代理就是代替处理的意思,一个对象有能力代替另一个对象处理某一件事。代理,这个词在我们的日常生活中也不陌生,比如在购物、旅游等场景中,我们经常会委托别人代替...【详细内容】
2024-03-26  萤火架构  微信公众号  Tags:正向代理   点击:(14)  评论:(0)  加入收藏
看一遍就理解:IO模型详解
前言大家好,我是程序员田螺。今天我们一起来学习IO模型。在本文开始前呢,先问问大家几个问题哈~什么是IO呢?什么是阻塞非阻塞IO?什么是同步异步IO?什么是IO多路复用?select/epoll...【详细内容】
2024-03-26  捡田螺的小男孩  微信公众号  Tags:IO模型   点击:(10)  评论:(0)  加入收藏
站内最新
站内热门
站内头条