最近有个需求,需要添加滑块拼图验证码,网上了解了一些生成校验方式,下面写个 demo实现一下。
一、滑块拼图验证码生成 1、生成思路滑块拼图验证码生成思路:
- 在若干原图中随机一张原图,然后改变原图大小为规范的大图对象
- 随机生成(X,Y)坐标
- 创建小图对象
- 随机生成拼图轮廓数据
- 从大图中裁剪拼图。抠原图,裁剪拼图
- 返回滑块拼图验证码信息:两个Base64字符串图片信息和(X,Y)坐标。
注意:
- 1、随机生成拼图轮廓数据是重点,然后裁剪拼图时根据需要它来抠原图,裁剪拼图。
- 2、拼图的凹凸信息,有两种处理方式
- 以小图的四边为边缘,外加凸圆弧或者内挖凹圆弧。
- 以小图的四边为最终边界,内加凸圆弧或者内挖凹圆弧,并且处理掉凹凸之外的颜色。
这里使用 以小图的四边为最终边界,上凹下凸,左无由凸,左边框高亮阴暗简单处理。
定义一个滑块拼图信息实体类:
@Data
public class SliderPuzzleInfo {
/**
* 大图宽度
*/
private Integer bigWidth;
/**
* 大图高度
*/
private Integer bigHeight;
/**
* 大图转BASE64字符串
*/
private String bigImageBase64;
/**
* 大图
*/
private BufferedImage bigImage;
/**
* 随机坐标Y
*/
private Integer posY;
/**
* 随机坐标X
*/
private Integer posX;
/**
* 小图宽度
*/
private Integer smallWidth;
/**
* 小图高度
*/
private Integer smallHeight;
/**
* 小图转BASE64字符串
*/
private String smallImageBase64;
/**
* 小图
*/
private BufferedImage smallImage;
}
生成具体代码如下:
public class SlidePuzzleUtil {
static Logger logger = LoggerFactory.getLogger(SlidePuzzleUtil.class);
// 大图宽度(原图裁剪拼图后的背景图)
private static final Integer bigWidth = 320;
// 大图高度
private static final Integer bigHeight = 160;
// 小图宽度(滑块拼图)
private static int smallWidth = 40;
// 小图高度
private static int smallHeight = 40;
// 小圆半径,即拼图上的凹凸轮廓半径
private static final Integer smallCircle = 8;
// 小圆距离点
private static int smallCircleR1 = smallCircle / 2;
public static void main(String[] args) throws IOException {
int i = 3;
File file = new File("D:/TempFiles/slide/slidebase" + i + ".png");
SliderPuzzleInfo sliderPuzzleInfo = SlidePuzzleUtil.createImage(new FileInputStream(file));
if (sliderPuzzleInfo == null) {
System.out.println("图片验证码生成失败");
}
File file1 = new File("D:/TempFiles/slide/demo2BigImage.png");
File file2 = new File("D:/TempFiles/slide/demo2SmallImage.png");
ImageIO.write(sliderPuzzleInfo.getBigImage(), "png", file1);
ImageIO.write(sliderPuzzleInfo.getSmallImage(), "png", file2);
}
/**
* 生成滑块拼图验证码
*
* @param input
* @return 返回null,表示生成滑块拼图验证码异常
*/
public static SliderPuzzleInfo createImage(InputStream input) {
SliderPuzzleInfo sliderPuzzleInfo = new SliderPuzzleInfo();
try {
// 1.获取原图对象
BufferedImage originalImage = ImageIO.read(input);
// 规范原图的大小
BufferedImage bigImage = resizeImage(originalImage, bigWidth, bigHeight, true);
// 2.随机生成离左上角的(X,Y)坐标,上限为 [bigWidth-smallWidth, bigHeight-smallHeight]。最好离大图左边远一点,上限不要紧挨着大图边界
Random random = new Random();
int randomX = random.nextInt(bigWidth - 4 * smallWidth - smallCircle) + 2 * smallWidth; // X范围:[2*smallWidth, bigWidth - 2*smallWidth - smallCircle)
int randomY = random.nextInt(bigHeight - smallHeight - 2 * smallCircle) + smallCircle; // Y范围:[smallCircle, bigHeight - smallHeight - smallCircle)
logger.info("原图大小:{} x {},大图大小:{} x {},随机生成的坐标:(X,Y)=({},{})", originalImage.getWidth(), originalImage.getHeight(), bigImage.getWidth(), bigImage.getHeight(),
randomX, randomY);
// 3.创建小图对象
BufferedImage smallImage = new BufferedImage(smallWidth, smallHeight, BufferedImage.TYPE_4BYTE_ABGR);
// 4.随机生成拼图轮廓数据
int[][] slideTemplateData = getSlideTemplateData(smallWidth, smallHeight, smallCircle, smallCircleR1);
// 5.从大图中裁剪拼图。抠原图,裁剪拼图
cutByTemplate(bigImage, smallImage, slideTemplateData, randomX, randomY);
sliderPuzzleInfo.setPosX(randomX);
sliderPuzzleInfo.setPosY(randomY);
sliderPuzzleInfo.setBigWidth(bigWidth);
sliderPuzzleInfo.setBigHeight(bigHeight);
sliderPuzzleInfo.setBigImage(bigImage);
sliderPuzzleInfo.setBigImageBase64(getImageBASE64(bigImage));
sliderPuzzleInfo.setSmallWidth(smallWidth);
sliderPuzzleInfo.setSmallHeight(smallHeight);
sliderPuzzleInfo.setSmallImage(smallImage);
sliderPuzzleInfo.setSmallImageBase64(getImageBASE64(smallImage));
} catch (Exception e) {
sliderPuzzleInfo = null;
logger.info("创建生成滑块拼图验证码异常,e=", e);
} finally {
return sliderPuzzleInfo;
}
}
/**
* 获取拼图图轮廓数据
* @param smallWidth
* @param smallHeight
* @param smallCircle
* @param r1
* @return 0和1,其中0表示没有颜色,1有颜色
*/
private static int[][] getSlideTemplateData(int smallWidth, int smallHeight, int smallCircle, int r1) {
// 拼图轮廓数据
int[][] data = new int[smallWidth][smallHeight];
//拼图去掉凹凸的白色距离
int xBlank = smallWidth - smallCircle - smallCircleR1; // 不写smallCircleR1时,凹凸为半圆
int yBlank = smallHeight - smallCircle - smallCircleR1;
// 圆的位置
int rxa = xBlank / 2;
int ryb = smallHeight - smallCircle;
double rPow = Math.pow(smallCircle, 2);
/**
* 计算需要的拼图轮廓(方块和凹凸),用二维数组来表示,二维数组有两张值,0和1,其中0表示没有颜色,1有颜色
* 圆的标准方程 (x-a)²+(y-b)²=r²,标识圆心(a,b),半径为r的圆
*/
for (int i = 0; i
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?