您当前的位置: 首页 >  Java

Charge8

暂无认证

  • 4浏览

    0关注

    447博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

Java实现滑块拼图验证码校验

Charge8 发布时间:2022-06-03 14:48:17 ,浏览量:4

最近有个需求,需要添加滑块拼图验证码,网上了解了一些生成校验方式,下面写个 demo实现一下。

一、滑块拼图验证码生成 1、生成思路

滑块拼图验证码生成思路:

  1. 在若干原图中随机一张原图,然后改变原图大小为规范的大图对象
  2. 随机生成(X,Y)坐标
  3. 创建小图对象
  4. 随机生成拼图轮廓数据
  5. 从大图中裁剪拼图。抠原图,裁剪拼图
  6. 返回滑块拼图验证码信息:两个Base64字符串图片信息和(X,Y)坐标。

注意:

  • 1、随机生成拼图轮廓数据是重点,然后裁剪拼图时根据需要它来抠原图,裁剪拼图。
  • 2、拼图的凹凸信息,有两种处理方式
    • 以小图的四边为边缘,外加凸圆弧或者内挖凹圆弧。
    • 以小图的四边为最终边界,内加凸圆弧或者内挖凹圆弧,并且处理掉凹凸之外的颜色。
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             
关注
打赏
1664721914
查看更多评论
0.0424s