Java实现滑动验证码生成(后端工具类)
weixin_52707625 人气:0一、滑动验证码生成思路
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; } }
四、测试结果
这里看滑块是白色背景,实际上是透明的
生成完成
加载全部内容