Java实现滑动验证码生成(后端工具类)
作者:weixin_52707625 发布时间:2022-02-07 01:26:37
标签:Java,滑动,验证码
一、滑动验证码生成思路
1、随机选择一张图片
2、生成滑块起点位置(x, y)
3、生成滑块轮廓
4、抠出滑块
5、将滑块部位去除颜色
二、主要方法
这里使用的方法是:先抠出中间的正方形,再将凹凸槽的RGB渲染上去
1、扣主体
将自定义滑块大小扩大三分之二,用来做凸槽
2、抠凸槽
因为凸槽是个圆,所以可通过圆的标准方程
三、生成代码
滑块验证码实体类
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author: Yang
* @create: 2022-10-25
* @Description: 滑动验证码实体
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ImageSlideVerify {
private String bgImg;// 底部图片
private String blockImg;// 滑块图片
private Integer x;// 开始x
private Integer y;// 开始y
private Integer bound;// 误差值
}
生成滑块验证码
import com.yang.domain.vo.ImageSlideVerify;
import org.apache.tomcat.util.codec.binary.Base64;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Transparency;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Random;
import java.util.UUID;
import javax.imageio.ImageIO;
/**
* 滑动验证码
* @author Yang
*
*/
public class ImageSlideVerifyUtil {
private static Integer x, y;// x , y轴起点位置
private static Integer blockSize; // 块大小
public static void main(String[] args) throws IOException {
File file = new File("4.jpeg");
cutting(file, 80);
cutting(file);
}
// 切割
public static ImageSlideVerify cutting(File file, int size) {
FileInputStream fis;
blockSize = size;
try {
fis = new FileInputStream(file);
BufferedImage image = ImageIO.read(fis);// 将文件流转图像流
// 生成圆位置
Integer cp[] = circle();// 下标对应:上右下左
// 生成滑块
BufferedImage img = generateMin(image, image.getWidth(), image.getHeight(), size, cp);
// 图片转base64
String bgImg = imageToBase64(image);
String blockImg = imageToBase64(img);
// TODO 保存图片:用于测试,测试完毕删除
// ImageIO.write(img, "png", new File("4-1.png"));
// ImageIO.write(image, "png", new File("4-2.png"));
ImageSlideVerify imageSlideVerify = new ImageSlideVerify(bgImg, blockImg, x, y, 3);
return imageSlideVerify;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
// 切割
public static ImageSlideVerify cutting(File file) {
return cutting(file, 60);
}
// 圆的位置
private static Integer[] circle() {
Integer c[] = new Integer[4];// 四个位置有圆,0代表无,1代表有,下标对应上、右、下、左
boolean flag = false;// 记录是否有圆
while(!flag) {// 如果没有圆,则继续循环,至少要有一个圆(凸槽)
for(int i = 0; i < 4; i++) {
c[i] = new Random().nextInt(2);
if(c[i] == 1) {
flag = true;
}
}
}
return c;
}
/**
* 生成小滑块位置
* @param img
* @param width 图片宽度
* @param height 图片高度
* @param size 滑块大小, 正方形,宽高相等
* @return
* @throws IOException
*/
private static BufferedImage generateMin(BufferedImage img, int width, int height, int size, Integer[] cp) throws IOException {
/**
* 滑块大小:定义大小 + 三分之一
*/
int size1 = size + (size / 3 * 2);
/**
* 最大起点位置
* x:宽度 - 滑块大小
* y:高度 - 滑块大小
*/
int maxX = width - ( size1 );
int maxY = height - ( size1 );
// 生成滑块开始位置
x = new Random().nextInt(maxX);
y = new Random().nextInt(maxY);
// 创建滑块图像
BufferedImage img1 = new BufferedImage(size1, size1, BufferedImage.TYPE_INT_RGB);
Graphics2D gr = img1.createGraphics();
// 图像背景透明
img1 = gr.getDeviceConfiguration().createCompatibleImage(size1, size1, Transparency.TRANSLUCENT);
// 拷贝rgb
for(int i = 0; i < size1; i++) {
for(int j = 0; j < size1; j++) {
if(i < size / 3 || i > size + size / 3 || j < size / 3 || j > size + size / 3) {
continue;
}
// 渲染RGB
img1.setRGB(i, j, img.getRGB(i + x, j + y));
// 将原图像素点覆盖白色
Color color = new Color(255,255,255);
img.setRGB(i + x, j + y, color.getRGB());
}
}
// 设置圆(凸槽)
setCircle(img, img1, x, y, cp);
return img1;
}
/**
* 设置圆
* @param oldImg
* @param img
* @param x
* @param y
* @param cp
* @throws IOException
*/
private static void setCircle(BufferedImage oldImg, BufferedImage img, int x, int y, Integer[] cp) throws IOException {
// 以白色覆盖原图像素点
Color color = new Color(255,255,255);
int d = blockSize / 3 + 2; // 直径
int r = d / 2;// 半径
/**
* TODO 以下待改进
*/
if(cp[0] == 1) {// 上
// 中心位置
int w = img.getWidth() / 2;
for(int i = w - r, r1 = 0; i < w + r; i++, r1++) {
for(int j = 0, r2 = 0; j < d; j++, r2++) {
/**
* 判断点是否在圆内:点p(x, y), 圆心r(x, y)
* 有:(px - rx)^2 + (py - ry)^2 <= rx*ry
*/
if((r1 - r) * (r1 - r) + (r2 - r) * (r2 - 11) <= r * r) {
if(oldImg.getRGB(x + i, y + j) == color.getRGB()) {
continue;
}
img.setRGB(i, j, oldImg.getRGB(x + i, y + j));
// 对应位置透明
oldImg.setRGB(x + i, y + j, color.getRGB());
}
}
}
}
if(cp[1] == 1) {// 右
// 中心位置
int h = img.getHeight() / 2;
for(int i = img.getWidth() - d, r1 = 0; i < img.getWidth(); i++, r1++) {
for(int j = h - r, r2 = 0; j < h + r; j++, r2++) {
if((r1 - r) * (r1 - r) + (r2 - r) * (r2 - r) <= r * r) {
if(oldImg.getRGB(x + i, y + j) == color.getRGB()) continue;
img.setRGB(i, j, oldImg.getRGB(x + i, y + j));
// 对应位置透明
oldImg.setRGB(x + i, y + j, color.getRGB());
}
}
}
}
if(cp[2] == 1) {// 下
// 中心位置
int w = img.getWidth() / 2;
for(int i = w - r, r1 = 0; i < w + r; i++, r1++) {
for(int j = img.getHeight() - d, r2 = 0; j < img.getHeight(); j++, r2++) {
if((r1 - r) * (r1 - r) + (r2 - r) * (r2 - r) <= r * r) {
if(oldImg.getRGB(x + i, y + j) == color.getRGB()) continue;
img.setRGB(i, j, oldImg.getRGB(x + i, y + j));
// 对应位置透明
oldImg.setRGB(x + i, y + j, color.getRGB());
}
}
}
}
if(cp[3] == 1) {// 左
// 中心位置
int h = img.getHeight() / 2;
for(int i = 0, r1 = 0; i < d; i++, r1++) {
for(int j = h - r, r2 = 0; j < h + r; j++, r2++) {
if((r1 - r) * (r1 - r) + (r2 - r) * (r2 - r) <= r * r) {
if(oldImg.getRGB(x + i, y + j) == color.getRGB()) continue;
img.setRGB(i, j, oldImg.getRGB(x + i, y + j));
// 对应位置透明
oldImg.setRGB(x + i, y + j, color.getRGB());
}
}
}
}
}
/**
* 图像转base64
* @param img
* @return
*/
private static String imageToBase64(BufferedImage img){
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
// 设置图片的格式
ImageIO.write(img, "png", stream);
byte[] bytes = Base64.encodeBase64(stream.toByteArray());
String base64 = new String(bytes);
return "data:image/jpeg;base64,"+base64;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
}
四、测试结果
这里看滑块是白色背景,实际上是透明的
生成完成
web前端代码
来源:https://blog.csdn.net/weixin_52707625/article/details/127526881


猜你喜欢
- C#Process OutputDataReceived事件不触发问题描述项目需要用cmd调用其它软件,实时获取软件处理结果,并根据获取到的
- 引言MyBatis-Plus | 最优雅最简洁地完成数据库操作是对MyBatis-Plus的功能进行简单介绍,虽然是介绍,也让我们领略到他的
- 一、简介:介绍两种使用 BitmapTransformation 来实现 Glide 加载圆形图片和圆角图片的方法。Glide 并不能直接支
- WebService是一种跨编程语言和跨操作系统平台的远程调用技术所谓远程调用,就是一台计算机a上的一个程序可以调用到另外一台计算机b上的一
- 大致分为以下几个方面:一些查询指令整理使用SQL语句进行特殊查询检测表字段是否存在数据库升级数据库表字段赋初始值一、查询指令整理1.链式执行
- 1. 可变参数在JDK1.5之后,如果我们定义一个方法需要接受多个参数,并且多个参数类型一致,我们可以对其简化.格式:修饰符 返回值类型 方
- 1.下载AndroidStudioAndroidStudio官网下载地址:http://developer.android.com/intl
- Android ToggleButton 详解在Android的开发过程中,对于ToggleButton的使用频率也是相当的高的,下面我就来
- fork()函数用于从已存在的进程中创建一个新进程。新进程称为子进程,而园进程称为父进程。使用fork()函数得到的子进程是父进程的一个复制
- 在Java的线程执行中,不管是直接继承Thread的方式,还是实现Runnable接口的方式,都不会获取到线程执行的返回结果。这样如果线程在
- 随着目前微信越来越火,所以研究微信的人也就越来越多,这不前一段时间,我们公司就让我做一个微信公众号中问卷调查发红包功能,经过一段时间的研究,
- application.properties大家都不陌生,我们在开发的时候,经常使用它来配置一些可以手动修改而且不用编译的变量,这样的作用在
- 本文是项目中使用了websocket进行一些数据的推送,对比项目做了一个demo,ws的相关问题不做细数,仅做一下记录。此demo针对ws的
- 目录springboot autoconfig的一些实验SpringBoot autoconfig部分注解说明SpringBoot auto
- 1.定义多态是同一个行为具有多个不同表现形式或形态的能力。多态性意味着有多重形式。在面向对象编程范式中,多态性往往表现为"一个接口
- 什么是JSON?JSON (JavaScript Object Notation) is a lightweight data-interc
- Android Studio是Android的官方IDE。它是专为Android而打造,可以加快您的开发速度,帮助您为每款Android设备
- 关于Path之前写的也很多了,例如path绘制线,path绘制一阶,二阶和三阶贝塞尔路径,这些都是path的基本用法。今天我要带大家看的是P
- 概述在 NAudio 中, 常用类型有 WaveIn, WaveOut, WaveStream, WaveFileWriter, WaveF
- 重新指定分配默认值的参数时,可以显式地为指定参数名称赋值,隐式指定的时候,是根据方法参数的顺序,靠c#编译器的推断。 代码示例: void