mirror of
https://github.com/dromara/tianai-captcha.git
synced 2026-05-07 06:04:34 +08:00
U 优化点选验证码,用于将来支持语序验证码等相关具有联想的点击类验证码
This commit is contained in:
+36
-21
@@ -31,7 +31,6 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
|
|||||||
@Setter
|
@Setter
|
||||||
protected Integer interferenceCount = 2;
|
protected Integer interferenceCount = 2;
|
||||||
|
|
||||||
|
|
||||||
public AbstractClickImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager) {
|
public AbstractClickImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager) {
|
||||||
super(imageCaptchaResourceManager);
|
super(imageCaptchaResourceManager);
|
||||||
}
|
}
|
||||||
@@ -53,9 +52,13 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
|
|||||||
List<ClickImageCheckDefinition> clickImageCheckDefinitionList = new ArrayList<>(interferenceCount);
|
List<ClickImageCheckDefinition> clickImageCheckDefinitionList = new ArrayList<>(interferenceCount);
|
||||||
int allImages = interferenceCount + checkClickCount;
|
int allImages = interferenceCount + checkClickCount;
|
||||||
int avg = bgImage.getWidth() / allImages;
|
int avg = bgImage.getWidth() / allImages;
|
||||||
|
List<String> imgTips = randomGetClickImgTips(allImages);
|
||||||
|
if (allImages < imgTips.size()) {
|
||||||
|
throw new IllegalStateException("随机生成点击图片小于请求数量, 请求生成数量=" + allImages + ",实际生成数量=" + imgTips.size());
|
||||||
|
}
|
||||||
for (int i = 0; i < allImages; i++) {
|
for (int i = 0; i < allImages; i++) {
|
||||||
// 随机获取点击图片
|
// 随机获取点击图片
|
||||||
ImgWrapper imgWrapper = randomGetClickImg();
|
ImgWrapper imgWrapper = getClickImg(imgTips.get(i));
|
||||||
BufferedImage image = imgWrapper.getImage();
|
BufferedImage image = imgWrapper.getImage();
|
||||||
int clickImgWidth = image.getWidth();
|
int clickImgWidth = image.getWidth();
|
||||||
int clickImgHeight = image.getHeight();
|
int clickImgHeight = image.getHeight();
|
||||||
@@ -78,17 +81,10 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
|
|||||||
clickImageCheckDefinition.setHeight(clickImgHeight);
|
clickImageCheckDefinition.setHeight(clickImgHeight);
|
||||||
clickImageCheckDefinitionList.add(clickImageCheckDefinition);
|
clickImageCheckDefinitionList.add(clickImageCheckDefinition);
|
||||||
}
|
}
|
||||||
// 打乱
|
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList = getCheckClickImageCheckDefinitionList(clickImageCheckDefinitionList,
|
||||||
Collections.shuffle(clickImageCheckDefinitionList);
|
checkClickCount);
|
||||||
// 拿出参与校验的数据
|
// wrap
|
||||||
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList = new ArrayList<>(checkClickCount);
|
return wrapClickImageCaptchaInfo(param, bgImage, checkClickImageCheckDefinitionList);
|
||||||
for (int i = 0; i < checkClickCount; i++) {
|
|
||||||
ClickImageCheckDefinition clickImageCheckDefinition = clickImageCheckDefinitionList.get(i);
|
|
||||||
checkClickImageCheckDefinitionList.add(clickImageCheckDefinition);
|
|
||||||
}
|
|
||||||
// 将校验的文字生成提示图片
|
|
||||||
ImgWrapper tipImage = genTipImage(checkClickImageCheckDefinitionList);
|
|
||||||
return wrapClickImageCaptchaInfo(param, bgImage, tipImage.getImage(), checkClickImageCheckDefinitionList);
|
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
// 使用完后关闭流
|
// 使用完后关闭流
|
||||||
@@ -103,31 +99,50 @@ public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCa
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 随机获取点击的图片
|
* 从总的图片中 去除要校验的图片数据 以及顺序
|
||||||
*
|
*
|
||||||
* @return ImgWrapper
|
* @param allCheckDefinitionList 总的点选图片
|
||||||
|
* @param checkClickCount 参与校验的数据
|
||||||
|
* @return List<ClickImageCheckDefinition>
|
||||||
*/
|
*/
|
||||||
public abstract ImgWrapper randomGetClickImg();
|
protected List<ClickImageCheckDefinition> getCheckClickImageCheckDefinitionList(List<ClickImageCheckDefinition> allCheckDefinitionList,
|
||||||
|
Integer checkClickCount) {
|
||||||
|
// 打乱
|
||||||
|
Collections.shuffle(allCheckDefinitionList);
|
||||||
|
// 拿出参与校验的数据
|
||||||
|
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList = new ArrayList<>(checkClickCount);
|
||||||
|
for (int i = 0; i < checkClickCount; i++) {
|
||||||
|
ClickImageCheckDefinition clickImageCheckDefinition = allCheckDefinitionList.get(i);
|
||||||
|
checkClickImageCheckDefinitionList.add(clickImageCheckDefinition);
|
||||||
|
}
|
||||||
|
return checkClickImageCheckDefinitionList;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成 tip 图片
|
* 随机获取一组数据用于生成随机图
|
||||||
*
|
*
|
||||||
* @param imageCheckDefinitions imageCheckDefinitions
|
* @param tipSize tipSize
|
||||||
|
* @return List<String>
|
||||||
|
*/
|
||||||
|
protected abstract List<String> randomGetClickImgTips(int tipSize);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 随机获取点击的图片
|
||||||
|
*
|
||||||
|
* @param tip 提示数据,根据改数据生成图片
|
||||||
* @return ImgWrapper
|
* @return ImgWrapper
|
||||||
*/
|
*/
|
||||||
public abstract ImgWrapper genTipImage(List<ClickImageCheckDefinition> imageCheckDefinitions);
|
public abstract ImgWrapper getClickImg(String tip);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 包装 ImageCaptchaInfo
|
* 包装 ImageCaptchaInfo
|
||||||
*
|
*
|
||||||
* @param param param
|
* @param param param
|
||||||
* @param bgImage bgImage
|
* @param bgImage bgImage
|
||||||
* @param tipImage tipImage
|
|
||||||
* @param checkClickImageCheckDefinitionList checkClickImageCheckDefinitionList
|
* @param checkClickImageCheckDefinitionList checkClickImageCheckDefinitionList
|
||||||
* @return ImageCaptchaInfo
|
* @return ImageCaptchaInfo
|
||||||
*/
|
*/
|
||||||
public abstract ImageCaptchaInfo wrapClickImageCaptchaInfo(GenerateParam param, BufferedImage bgImage,
|
public abstract ImageCaptchaInfo wrapClickImageCaptchaInfo(GenerateParam param, BufferedImage bgImage,
|
||||||
BufferedImage tipImage,
|
|
||||||
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList);
|
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+20
-10
@@ -18,6 +18,7 @@ import java.awt.*;
|
|||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.ThreadLocalRandom;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@@ -47,8 +48,8 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
|
|||||||
protected int tipImageInterferencePointNum = 5;
|
protected int tipImageInterferencePointNum = 5;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 因为在画文字图形的时候 y 值不能准确通过 除法计算得出, 字体大小不一致中间的容错值不可估计,
|
* 因为在画文字图形的时候 y 值不能准确通过 除法计算得出, 字体大小不一致中间的容错值算不准确
|
||||||
* 所以通过 线性回归模型 计算出 intercept和coef 用于计算 容错值
|
* 方案: 通过 线性回归模型 计算出 intercept和coef 用于计算 容错值
|
||||||
* 训练数据为 宋体 字体大小为 30~150 随机选择7组数据进行训练, 训练后r2结果为 0.9967106324620846
|
* 训练数据为 宋体 字体大小为 30~150 随机选择7组数据进行训练, 训练后r2结果为 0.9967106324620846
|
||||||
*/
|
*/
|
||||||
protected float intercept = 0.39583333f;
|
protected float intercept = 0.39583333f;
|
||||||
@@ -63,6 +64,18 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected List<String> randomGetClickImgTips(int tipSize) {
|
||||||
|
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||||
|
List<String> tipList = new ArrayList<>(tipSize);
|
||||||
|
for (int i = 0; i < tipSize; i++) {
|
||||||
|
String randomWord = FontUtils.getRandomChar(random);
|
||||||
|
tipList.add(randomWord);
|
||||||
|
}
|
||||||
|
// 随机文字
|
||||||
|
return tipList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SneakyThrows({IOException.class, FontFormatException.class})
|
@SneakyThrows({IOException.class, FontFormatException.class})
|
||||||
protected void doInit(boolean initDefaultResource) {
|
protected void doInit(boolean initDefaultResource) {
|
||||||
@@ -85,14 +98,12 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
|
|||||||
this.font = font;
|
this.font = font;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void initDefaultResource() {
|
public void initDefaultResource() {
|
||||||
ResourceStore resourceStore = imageCaptchaResourceManager.getResourceStore();
|
ResourceStore resourceStore = imageCaptchaResourceManager.getResourceStore();
|
||||||
// 添加一些系统的资源文件
|
// 添加一些系统的资源文件
|
||||||
resourceStore.addResource(CaptchaTypeConstant.WORD_IMAGE_CLICK, new Resource(ClassPathResourceProvider.NAME, StandardSliderImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
|
resourceStore.addResource(CaptchaTypeConstant.WORD_IMAGE_CLICK, new Resource(ClassPathResourceProvider.NAME, StandardSliderImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ImgWrapper genTipImage(List<ClickImageCheckDefinition> imageCheckDefinitions) {
|
public ImgWrapper genTipImage(List<ClickImageCheckDefinition> imageCheckDefinitions) {
|
||||||
String tips = imageCheckDefinitions.stream().map(ClickImageCheckDefinition::getTip).collect(Collectors.joining());
|
String tips = imageCheckDefinitions.stream().map(ClickImageCheckDefinition::getTip).collect(Collectors.joining());
|
||||||
// 生成随机颜色
|
// 生成随机颜色
|
||||||
@@ -107,29 +118,28 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImgWrapper randomGetClickImg() {
|
public ImgWrapper getClickImg(String tip) {
|
||||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||||
// 随机文字
|
|
||||||
String randomWord = FontUtils.getRandomChar(random);
|
|
||||||
// 随机颜色
|
// 随机颜色
|
||||||
Color randomColor = CaptchaImageUtils.getRandomColor(random);
|
Color randomColor = CaptchaImageUtils.getRandomColor(random);
|
||||||
// 随机角度
|
// 随机角度
|
||||||
int randomDeg = ThreadLocalRandom.current().nextInt(0, 85);
|
int randomDeg = ThreadLocalRandom.current().nextInt(0, 85);
|
||||||
BufferedImage fontImage = CaptchaImageUtils.drawWordImg(randomColor,
|
BufferedImage fontImage = CaptchaImageUtils.drawWordImg(randomColor,
|
||||||
randomWord,
|
tip,
|
||||||
font,
|
font,
|
||||||
currentFontTopCoef,
|
currentFontTopCoef,
|
||||||
clickImgWidth,
|
clickImgWidth,
|
||||||
clickImgHeight,
|
clickImgHeight,
|
||||||
randomDeg);
|
randomDeg);
|
||||||
return new ImgWrapper(fontImage, randomWord);
|
return new ImgWrapper(fontImage, tip);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ImageCaptchaInfo wrapClickImageCaptchaInfo(GenerateParam param, BufferedImage bgImage,
|
public ImageCaptchaInfo wrapClickImageCaptchaInfo(GenerateParam param, BufferedImage bgImage,
|
||||||
BufferedImage tipImage,
|
|
||||||
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList) {
|
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList) {
|
||||||
|
// 提示图片
|
||||||
|
BufferedImage tipImage = genTipImage(checkClickImageCheckDefinitionList).getImage();
|
||||||
ImageCaptchaInfo clickImageCaptchaInfo = new ImageCaptchaInfo();
|
ImageCaptchaInfo clickImageCaptchaInfo = new ImageCaptchaInfo();
|
||||||
clickImageCaptchaInfo.setBackgroundImage(transform(bgImage, param.getBackgroundFormatName()));
|
clickImageCaptchaInfo.setBackgroundImage(transform(bgImage, param.getBackgroundFormatName()));
|
||||||
clickImageCaptchaInfo.setSliderImage(transform(tipImage, param.getSliderFormatName()));
|
clickImageCaptchaInfo.setSliderImage(transform(tipImage, param.getSliderFormatName()));
|
||||||
|
|||||||
Reference in New Issue
Block a user