Java實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼生成(后端工具類)
一、滑動(dòng)驗(yàn)證碼生成思路
1、隨機(jī)選擇一張圖片
2、生成滑塊起點(diǎn)位置(x, y)
3、生成滑塊輪廓
4、摳出滑塊
5、將滑塊部位去除顏色

二、主要方法
這里使用的方法是:先摳出中間的正方形,再將凹凸槽的RGB渲染上去
1、扣主體
將自定義滑塊大小擴(kuò)大三分之二,用來做凸槽
2、摳凸槽

因?yàn)橥共凼莻€(gè)圓,所以可通過圓的標(biāo)準(zhǔn)方程
三、生成代碼
滑塊驗(yàn)證碼實(shí)體類
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author: Yang
* @create: 2022-10-25
* @Description: 滑動(dòng)驗(yàn)證碼實(shí)體
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class ImageSlideVerify {
private String bgImg;// 底部圖片
private String blockImg;// 滑塊圖片
private Integer x;// 開始x
private Integer y;// 開始y
private Integer bound;// 誤差值
}
生成滑塊驗(yàn)證碼
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;
/**
* 滑動(dòng)驗(yàn)證碼
* @author Yang
*
*/
public class ImageSlideVerifyUtil {
private static Integer x, y;// x , y軸起點(diǎn)位置
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);// 將文件流轉(zhuǎn)圖像流
// 生成圓位置
Integer cp[] = circle();// 下標(biāo)對(duì)應(yīng):上右下左
// 生成滑塊
BufferedImage img = generateMin(image, image.getWidth(), image.getHeight(), size, cp);
// 圖片轉(zhuǎn)base64
String bgImg = imageToBase64(image);
String blockImg = imageToBase64(img);
// TODO 保存圖片:用于測(cè)試,測(cè)試完畢刪除
// 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];// 四個(gè)位置有圓,0代表無,1代表有,下標(biāo)對(duì)應(yīng)上、右、下、左
boolean flag = false;// 記錄是否有圓
while(!flag) {// 如果沒有圓,則繼續(xù)循環(huán),至少要有一個(gè)圓(凸槽)
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 {
/**
* 滑塊大?。憾x大小 + 三分之一
*/
int size1 = size + (size / 3 * 2);
/**
* 最大起點(diǎn)位置
* x:寬度 - 滑塊大小
* y:高度 - 滑塊大小
*/
int maxX = width - ( size1 );
int maxY = height - ( size1 );
// 生成滑塊開始位置
x = new Random().nextInt(maxX);
y = new Random().nextInt(maxY);
// 創(chuàng)建滑塊圖像
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));
// 將原圖像素點(diǎn)覆蓋白色
Color color = new Color(255,255,255);
img.setRGB(i + x, j + y, color.getRGB());
}
}
// 設(shè)置圓(凸槽)
setCircle(img, img1, x, y, cp);
return img1;
}
/**
* 設(shè)置圓
* @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 {
// 以白色覆蓋原圖像素點(diǎn)
Color color = new Color(255,255,255);
int d = blockSize / 3 + 2; // 直徑
int r = d / 2;// 半徑
/**
* TODO 以下待改進(jìn)
*/
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++) {
/**
* 判斷點(diǎn)是否在圓內(nèi):點(diǎn)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));
// 對(duì)應(yīng)位置透明
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));
// 對(duì)應(yīng)位置透明
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));
// 對(duì)應(yīng)位置透明
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));
// 對(duì)應(yīng)位置透明
oldImg.setRGB(x + i, y + j, color.getRGB());
}
}
}
}
}
/**
* 圖像轉(zhuǎn)base64
* @param img
* @return
*/
private static String imageToBase64(BufferedImage img){
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
// 設(shè)置圖片的格式
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;
}
}
四、測(cè)試結(jié)果


這里看滑塊是白色背景,實(shí)際上是透明的
生成完成
到此這篇關(guān)于Java實(shí)現(xiàn)滑動(dòng)驗(yàn)證碼生成(后端工具類)的文章就介紹到這了,更多相關(guān)Java滑動(dòng)驗(yàn)證碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實(shí)現(xiàn)圖片寫入高清字體及帶邊框的方法
這篇文章主要介紹了java實(shí)現(xiàn)圖片寫入高清字體及帶邊框的方法,涉及java針對(duì)圖片及文字的相關(guān)操作技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-07-07
Spring Boot整合Mybatis Plus和Swagger2的教程詳解
這篇文章主要介紹了Spring Boot整合Mybatis Plus和Swagger2的教程,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02
MyBatisPlus中@TableField注解的基本使用
這篇文章主要介紹了MyBatisPlus中@TableField注解的基本使用,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07
springboot使用Logback把日志輸出到控制臺(tái)或輸出到文件
這篇文章給大家介紹springboot項(xiàng)目使用日志工具Logback把日志不僅輸出到控制臺(tái),也可以輸出到文件的操作方法,本文通過實(shí)例圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧2020-10-10
java實(shí)現(xiàn)騰訊ocr圖片識(shí)別接口調(diào)用
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)騰訊ocr圖片識(shí)別接口調(diào)用,拍車牌識(shí)別車牌號(hào)功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-11-11
解決 IDEA 創(chuàng)建 Gradle 項(xiàng)目沒有src目錄問題
這篇文章主要介紹了解決 IDEA 創(chuàng)建 Gradle 項(xiàng)目沒有src目錄問題,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-06-06
Spring MVC如何使用@RequestParam注解獲取參數(shù)
這篇文章主要介紹了Spring MVC實(shí)現(xiàn)使用@RequestParam注解獲取參數(shù)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-10-10
Java使用poi導(dǎo)出ppt文件的實(shí)現(xiàn)代碼
Apache POI 是用Java編寫的免費(fèi)開源的跨平臺(tái)的 Java API,Apache POI提供API給Java對(duì)Microsoft Office格式檔案讀和寫的功能。本文給大家介紹Java使用poi導(dǎo)出ppt文件的實(shí)現(xiàn)代碼,需要的朋友參考下吧2021-06-06
詳解如何在SpringBoot中優(yōu)雅地重試調(diào)用第三方API
在實(shí)際的應(yīng)用中,我們經(jīng)常需要調(diào)用第三方API來獲取數(shù)據(jù)或執(zhí)行某些操作,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-12-12

