This commit is contained in:
天爱有情
2022-04-28 09:02:47 +08:00
parent 4b6eef77eb
commit 44f58f1c93
13 changed files with 412 additions and 32 deletions
@@ -306,4 +306,15 @@ public class CaptchaImageUtils {
}
return newImage;
}
public static void main(String[] args) {
char randomChar = getRandomChar();
System.out.println(randomChar);
}
public static char getRandomChar() {
return (char)(0x4e00 + (int)(Math.random()*(0x9fa5 - 0x4e00 + 1)));
}
}
@@ -0,0 +1,17 @@
package cloud.tianai.captcha.template.slider.common.util;
/**
* @Author: 天爱有情
* @date 2022/4/27 11:34
* @Description 字体工具包
*/
public class FontUtils {
public static char getRandomChar() {
return (char)(0x4e00 + (int)(Math.random()*(0x9fa5 - 0x4e00 + 1)));
}
}
@@ -56,7 +56,8 @@ public abstract class AbstractImageCaptchaGenerator implements ImageCaptchaGener
* @param formatType 格式化类型
* @return String
*/
public String transform(BufferedImage bufferedImage, String formatType) throws IOException {
@SneakyThrows(IOException.class)
public String transform(BufferedImage bufferedImage, String formatType) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ImageIO.write(bufferedImage, formatType, byteArrayOutputStream);
//转换成字节码
@@ -13,4 +13,6 @@ public interface CaptchaTypeConstant {
String ROTATE = "ROTATE";
/** 拼接.*/
String CONCAT = "CONCAT";
/** 文字点选.*/
String WORD_CLICK = "WORD_CLICK";
}
@@ -30,8 +30,12 @@ public class ImageCaptchaInfo {
private Integer sliderImageWidth;
/** 滑块图片高度. */
private Integer sliderImageHeight;
/** 随机值.*/
/** 随机值. */
private Integer randomX;
/** 容错值, 可以为空 默认 0.02容错,校验的时候用. */
private Float tolerant;
/** 验证码类型.*/
private String type;
/**
* 扩展字段
*/
@@ -43,7 +47,8 @@ public class ImageCaptchaInfo {
Integer bgImageHeight,
Integer sliderImageWidth,
Integer sliderImageHeight,
Integer randomX) {
Integer randomX,
String type) {
this.backgroundImage = backgroundImage;
this.sliderImage = sliderImage;
this.bgImageWidth = bgImageWidth;
@@ -51,6 +56,7 @@ public class ImageCaptchaInfo {
this.sliderImageWidth = sliderImageWidth;
this.sliderImageHeight = sliderImageHeight;
this.randomX = randomX;
this.type = type;
}
public static ImageCaptchaInfo of(String backgroundImage,
@@ -59,8 +65,9 @@ public class ImageCaptchaInfo {
Integer bgImageHeight,
Integer sliderImageWidth,
Integer sliderImageHeight,
Integer randomKey) {
return new ImageCaptchaInfo( backgroundImage, sliderImage, bgImageWidth, bgImageHeight, sliderImageWidth, sliderImageHeight, randomKey);
Integer randomKey,
String type) {
return new ImageCaptchaInfo(backgroundImage, sliderImage, bgImageWidth, bgImageHeight, sliderImageWidth, sliderImageHeight, randomKey, type);
}
}
@@ -1,5 +1,6 @@
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@@ -17,8 +18,8 @@ public class RotateImageCaptchaInfo extends ImageCaptchaInfo {
* 旋转多少度
*/
private Double degree;
/** 旋转图片的容错值大一点. */
public static final Float DEFAULT_TOLERANT = 0.05F;
public static RotateImageCaptchaInfo of(Double degree,
Integer randomX,
@@ -32,11 +33,14 @@ public class RotateImageCaptchaInfo extends ImageCaptchaInfo {
rotateImageCaptchaInfo.setDegree(degree);
rotateImageCaptchaInfo.setRandomX(randomX);
rotateImageCaptchaInfo.setBackgroundImage(backgroundImage);
rotateImageCaptchaInfo.setTolerant(DEFAULT_TOLERANT);
rotateImageCaptchaInfo.setSliderImage(sliderImage);
rotateImageCaptchaInfo.setBgImageWidth(bgImageWidth);
rotateImageCaptchaInfo.setBgImageHeight(bgImageHeight);
rotateImageCaptchaInfo.setSliderImageWidth(sliderImageWidth);
rotateImageCaptchaInfo.setSliderImageHeight(sliderImageHeight);
// 类型为旋转图片验证码
rotateImageCaptchaInfo.setType(CaptchaTypeConstant.ROTATE);
return rotateImageCaptchaInfo;
}
@@ -1,5 +1,6 @@
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@@ -36,7 +37,7 @@ public class SliderImageCaptchaInfo extends ImageCaptchaInfo {
sliderImageCaptchaInfo.setBgImageHeight(bgImageHeight);
sliderImageCaptchaInfo.setSliderImageWidth(sliderImageWidth);
sliderImageCaptchaInfo.setSliderImageHeight(sliderImageHeight);
sliderImageCaptchaInfo.setType(CaptchaTypeConstant.SLIDER);
return sliderImageCaptchaInfo;
}
@@ -0,0 +1,31 @@
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
import lombok.*;
import java.util.List;
/**
* @Author: 天爱有情
* @date 2022/4/27 15:33
* @Description 文字点选
*/
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class WordClickImageCaptchaInfo extends ImageCaptchaInfo {
private List<WordDefinition> checkWords;
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class WordDefinition {
private String word;
private Integer x;
private Integer y;
private Integer deg;
private Integer wordWidth;
private Integer wordHeight;
}
}
@@ -0,0 +1,217 @@
package cloud.tianai.captcha.template.slider.generator.impl;
import cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils;
import cloud.tianai.captcha.template.slider.common.util.FontUtils;
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
import cloud.tianai.captcha.template.slider.generator.common.model.dto.WordClickImageCaptchaInfo;
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
import cloud.tianai.captcha.template.slider.resource.ResourceStore;
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
import cloud.tianai.captcha.template.slider.resource.impl.provider.ClassPathResourceProvider;
import cloud.tianai.captcha.template.slider.resource.impl.provider.FileResourceProvider;
import lombok.Data;
import lombok.SneakyThrows;
import sun.font.FontDesignMetrics;
import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.*;
import java.util.concurrent.ThreadLocalRandom;
import static cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils.wrapFile2BufferedImage;
import static cloud.tianai.captcha.template.slider.generator.impl.StandardSliderImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_RESOURCE_PATH;
/**
* @Author: 天爱有情
* @date 2022/4/27 11:46
* @Description 点选验证码
*/
@Data
public class StandardClickImageCaptchaGenerator extends AbstractImageCaptchaGenerator {
protected ImageCaptchaResourceManager imageCaptchaResourceManager;
protected Integer checkFontCount = 4;
protected Integer interferenceCount = checkFontCount + 2;
protected Font font;
protected List<Color> randomColors = Arrays.asList(Color.PINK, Color.BLUE, Color.GREEN, Color.BLACK);
@SneakyThrows
public StandardClickImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager, boolean initDefaultResource) {
this.imageCaptchaResourceManager = imageCaptchaResourceManager;
if (initDefaultResource) {
initDefaultResource();
}
Resource fontResource = new Resource("", "META-INF/fonts/SIMSUN.TTC");
InputStream inputStream = new ClassPathResourceProvider().doGetResourceInputStream(fontResource);
this.font = Font.createFont(Font.TRUETYPE_FONT, inputStream);
this.font = font.deriveFont(Font.BOLD, 50);
}
public StandardClickImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager,
boolean initDefaultResource,
Font font) {
this.imageCaptchaResourceManager = imageCaptchaResourceManager;
this.font = font;
if (initDefaultResource) {
initDefaultResource();
}
}
public void initDefaultResource() {
ResourceStore resourceStore = imageCaptchaResourceManager.getResourceStore();
// 添加一些系统的资源文件
resourceStore.addResource(CaptchaTypeConstant.WORD_CLICK, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
}
@Override
public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) {
// 文字点选验证码不需要模板 只需要背景图
Collection<InputStream> inputStreams = new LinkedList<>();
try {
Resource resourceImage = imageCaptchaResourceManager.randomGetResource(param.getType());
InputStream resourceInputStream = imageCaptchaResourceManager.getResourceInputStream(resourceImage);
inputStreams.add(resourceInputStream);
BufferedImage bgImage = wrapFile2BufferedImage(resourceInputStream);
Graphics2D graphics = (Graphics2D) bgImage.getGraphics();
List<WordClickImageCaptchaInfo.WordDefinition> wordDefinitionList = new ArrayList<>(interferenceCount);
for (int i = 0; i < interferenceCount; i++) {
// 随机角度
FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
// 随机文字
String randomWord = String.valueOf(FontUtils.getRandomChar());
int wordWidth = metrics.stringWidth(randomWord);
int wordHeight = metrics.getHeight();
// 随机颜色
Color randomColor = randomColor();
// 随机x
int randomX = ThreadLocalRandom.current().nextInt(10, bgImage.getWidth() - wordWidth);
// 随机y
int randomY = ThreadLocalRandom.current().nextInt(10, bgImage.getHeight() - wordHeight);
int randomDeg = ThreadLocalRandom.current().nextInt(0, 85);
AffineTransform affineTransform = new AffineTransform();
affineTransform.rotate(Math.toRadians(randomDeg));
Font rotatedFont = font.deriveFont(affineTransform);
graphics.setFont(rotatedFont);
graphics.setColor(randomColor);
graphics.drawString(randomWord, randomX, randomY + metrics.getAscent());
WordClickImageCaptchaInfo.WordDefinition wordDefinition = new WordClickImageCaptchaInfo.WordDefinition();
wordDefinition.setWord(randomWord);
wordDefinition.setX(randomX + wordWidth / 2);
wordDefinition.setY(randomY + wordHeight / 2);
wordDefinition.setDeg(randomDeg);
wordDefinition.setWordWidth(wordWidth);
wordDefinition.setWordHeight(wordHeight);
wordDefinitionList.add(wordDefinition);
}
// 背景图转换为字符串
// String bgImageStr = transform(bgImage, param.getBackgroundFormatName());
try {
ImageIO.write(bgImage, "jpeg", new FileOutputStream("C:\\Users\\Thinkpad\\Desktop\\123.jpg"));
} catch (IOException e) {
e.printStackTrace();
}
// 打乱 word
Collections.shuffle(wordDefinitionList);
// 拿出要校验的文字
List<WordClickImageCaptchaInfo.WordDefinition> checkWordDefinitionList = new ArrayList<>(checkFontCount);
for (int i = 0; i < checkFontCount; i++) {
checkWordDefinitionList.add(wordDefinitionList.get(i));
}
System.out.println(checkWordDefinitionList);
return null;
} finally {
// 使用完后关闭流
for (InputStream inputStream : inputStreams) {
try {
inputStream.close();
} catch (IOException e) {
// ignore
}
}
}
// return null;
}
protected Color randomColor() {
if (randomColors.size() == 1) {
return randomColors.get(0);
}
return randomColors.get(ThreadLocalRandom.current().nextInt(0, randomColors.size() - 1));
}
@Override
public ImageCaptchaResourceManager getImageResourceManager() {
return null;
}
public static void main(String[] args) throws IOException, FontFormatException {
Resource fontResource = new Resource("", "META-INF/fonts/SIMSUN.TTC");
InputStream inputStream = new ClassPathResourceProvider().doGetResourceInputStream(fontResource);
Font font = Font.createFont(Font.TRUETYPE_FONT, inputStream);
font = font.deriveFont(Font.BOLD, 100);
for (int i = 40; i < 60; i+=1) {
FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
Resource imageResource = new Resource("", "C:\\Users\\Thinkpad\\Desktop\\111.jpg");
inputStream = new FileResourceProvider().doGetResourceInputStream(imageResource);
BufferedImage bufferedImage = CaptchaImageUtils.wrapFile2BufferedImage(inputStream);
Graphics graphics = bufferedImage.getGraphics();
graphics.setColor(Color.PINK);
//设置角度
AffineTransform affineTransform = new AffineTransform();
affineTransform.rotate(Math.toRadians(180), i , -i);
Font rotatedFont = font.deriveFont(affineTransform);
graphics.setFont(rotatedFont);
char ch = FontUtils.getRandomChar();
// graphics.drawString(String.valueOf(ch), 10, 10+metrics.getAscent());
// graphics.drawString(String.valueOf(ch), 50, 50);
String randomWord = ""/*String.valueOf(FontUtils.getRandomChar())*/;
int wordWidth = metrics.stringWidth(randomWord);
int wordHeight = metrics.getHeight();
// //左边位置
int left = (bufferedImage.getWidth()-wordWidth)/2;
// //顶边位置+上升距离(原本字体基线位置对准画布的y坐标导致字体偏上ascent距离,加上ascent后下移刚好顶边吻合)
int top = (bufferedImage.getHeight()-wordHeight)/2+metrics.getAscent();
// 随机生成6个字的居中的 x 和 y
// for (int i = 0; i < 6; i++) {
// int randomX = ThreadLocalRandom.current().nextInt(10, bufferedImage.getWidth() - wordWidth);
// int randomY = ThreadLocalRandom.current().nextInt(10, bufferedImage.getHeight() - wordHeight);
graphics.drawString(randomWord, left, top);
System.out.println(randomWord + "-->x:" + (left + wordWidth / 2) + ",y:" + (left + wordHeight / 2));
// }
// graphics.drawString("居中文字",0,metrics.getAscent()); //基线对齐改为顶边对齐
ImageIO.write(bufferedImage, "jpeg", new FileOutputStream("C:\\Users\\Thinkpad\\Desktop\\111\\"+i+".jpg"));
}
}
}
@@ -27,7 +27,7 @@ import static cloud.tianai.captcha.template.slider.generator.impl.StandardSlider
*/
public class StandardConcatImageCaptchaGenerator extends AbstractImageCaptchaGenerator {
protected final ImageCaptchaResourceManager imageCaptchaResourceManager;
protected ImageCaptchaResourceManager imageCaptchaResourceManager;
public StandardConcatImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager, boolean initDefaultResource) {
this.imageCaptchaResourceManager = imageCaptchaResourceManager;
@@ -79,7 +79,16 @@ public class StandardConcatImageCaptchaGenerator extends AbstractImageCaptchaGen
private ImageCaptchaInfo wrapConcatCaptchaInfo(int randomX, BufferedImage bgImage, BufferedImage sliderImage, GenerateParam param) {
String backGroundImageBase64 = transform(bgImage, param.getBackgroundFormatName());
String sliderImageBase64 = transform(sliderImage, param.getSliderFormatName());
return ImageCaptchaInfo.of(backGroundImageBase64, sliderImageBase64, bgImage.getWidth(), bgImage.getHeight(), sliderImage.getWidth(), sliderImage.getHeight(), randomX);
ImageCaptchaInfo imageCaptchaInfo = ImageCaptchaInfo.of(backGroundImageBase64,
sliderImageBase64,
bgImage.getWidth(),
bgImage.getHeight(),
sliderImage.getWidth(),
sliderImage.getHeight(),
randomX,
CaptchaTypeConstant.CONCAT);
imageCaptchaInfo.setTolerant(0.05F);
return imageCaptchaInfo;
}
@Override
@@ -1,6 +1,8 @@
package cloud.tianai.captcha.template.slider.validator.impl;
import cloud.tianai.captcha.template.slider.common.util.CollectionUtils;
import cloud.tianai.captcha.template.slider.common.util.ObjectUtils;
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
import cloud.tianai.captcha.template.slider.validator.ImageCaptchaValidator;
import cloud.tianai.captcha.template.slider.validator.common.model.dto.SliderCaptchaTrack;
@@ -26,6 +28,10 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
@Setter
public float defaultTolerant = DEFAULT_TOLERANT;
public static final String PERCENTAGE_KEY = "percentage";
public static final String TOLERANT_KEY = "Tolerant";
public static final String TYPE_KEY = "type";
public SimpleImageCaptchaValidator() {
}
@@ -59,16 +65,28 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
public Map<String, Object> generateSliderCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo) {
Map<String, Object> map = new HashMap<>(8);
addPercentage(imageCaptchaInfo, map);
// 容错值
Float tolerant = imageCaptchaInfo.getTolerant();
if (tolerant != null && tolerant > 0) {
map.put(TOLERANT_KEY, tolerant);
}
// 类型
String type = imageCaptchaInfo.getType();
if (ObjectUtils.isEmpty(type)) {
type = CaptchaTypeConstant.SLIDER;
}
map.put(TYPE_KEY, type);
return map;
}
@Override
public boolean valid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData) {
Float oriPercentage = getPercentage(sliderCaptchaTrack, sliderCaptchaValidData);
if (oriPercentage == null) {
// 没读取到百分比
return false;
}
Float oriPercentage = getFloatParam(PERCENTAGE_KEY, sliderCaptchaValidData);
// 读容错值
Float tolerantData = getFloatParam(TOLERANT_KEY, sliderCaptchaValidData, defaultTolerant);
// 读验证码类型
String type = getStringParam(TYPE_KEY, sliderCaptchaValidData, CaptchaTypeConstant.SLIDER);
Integer bgImageWidth = sliderCaptchaTrack.getBgImageWidth();
if (bgImageWidth == null || bgImageWidth < 1) {
// 没有背景图片宽度
@@ -79,35 +97,74 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
// 没有滑动轨迹
return false;
}
return doValid(sliderCaptchaTrack, sliderCaptchaValidData, oriPercentage, tolerantData, type);
}
public boolean doValid(SliderCaptchaTrack sliderCaptchaTrack,
Map<String, Object> sliderCaptchaValidData,
Float oriPercentage,
Float tolerant,
String type) {
if (CaptchaTypeConstant.SLIDER.equals(type)
|| CaptchaTypeConstant.ROTATE.equals(type)
|| CaptchaTypeConstant.CONCAT.equals(type)) {
if (oriPercentage == null) {
// 没读取到百分比
return false;
}
List<SliderCaptchaTrack.Track> trackList = sliderCaptchaTrack.getTrackList();
// 取最后一个滑动轨迹
SliderCaptchaTrack.Track lastTrack = trackList.get(trackList.size() - 1);
// 计算百分比
float calcPercentage = calcPercentage(lastTrack.getX(), bgImageWidth);
float calcPercentage = calcPercentage(lastTrack.getX(), sliderCaptchaTrack.getBgImageWidth());
// 校验百分比
return checkPercentage(calcPercentage, oriPercentage);
return checkPercentage(calcPercentage, oriPercentage, tolerant);
}
// 不支持的类型
log.warn("校验验证码警告, 不支持的验证码类型:{}, 请手动扩展 cloud.tianai.captcha.template.slider.validator.impl.SimpleImageCaptchaValidator.doValid 进行校验扩展", type);
return false;
}
protected Float getPercentage(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData) {
Object percentage = sliderCaptchaValidData.get("percentage");
if (percentage != null) {
if (percentage instanceof Number) {
return ((Number) percentage).floatValue();
protected Float getFloatParam(String key, Map<String, Object> sliderCaptchaValidData) {
return getFloatParam(key, sliderCaptchaValidData, null);
}
protected Float getFloatParam(String key, Map<String, Object> sliderCaptchaValidData, Float defaultData) {
Object data = sliderCaptchaValidData.get(key);
if (data != null) {
if (data instanceof Number) {
return ((Number) data).floatValue();
}
try {
if (percentage instanceof String) {
return Float.parseFloat((String) percentage);
if (data instanceof String) {
return Float.parseFloat((String) data);
}
} catch (NumberFormatException e) {
log.error("从 sliderCaptchaValidData 读取到的 percentage无法转换成float类型, [{}]", percentage);
log.error("从 sliderCaptchaValidData 读取到的 " + key + "无法转换成float类型, [{}]", data);
throw e;
}
}
log.warn("无法从 sliderCaptchaValidData 获取到 percentage");
return null;
return defaultData;
}
protected String getStringParam(String key, Map<String, Object> sliderCaptchaValidData, String defaultData) {
Object data = sliderCaptchaValidData.get(key);
if (data != null) {
if (data instanceof String) {
return (String) data;
}
try {
return String.valueOf(data);
} catch (NumberFormatException e) {
log.error("从 sliderCaptchaValidData 读取到的 " + key + "无法转换成String类型, [{}]", data);
throw e;
}
}
return defaultData;
}
protected void addPercentage(ImageCaptchaInfo imageCaptchaInfo, Map<String, Object> sliderCaptchaValidData) {
float percentage = calcPercentage(imageCaptchaInfo.getRandomX(), imageCaptchaInfo.getBgImageWidth());
sliderCaptchaValidData.put("percentage", percentage);
sliderCaptchaValidData.put(PERCENTAGE_KEY, percentage);
}
}
Binary file not shown.
@@ -0,0 +1,23 @@
package example;
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
import cloud.tianai.captcha.template.slider.generator.impl.StandardClickImageCaptchaGenerator;
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
import cloud.tianai.captcha.template.slider.resource.impl.DefaultImageCaptchaResourceManager;
public class StandardWordClickImageCaptchaGeneratorTest {
public static void main(String[] args) {
ImageCaptchaResourceManager imageCaptchaResourceManager = new DefaultImageCaptchaResourceManager();
StandardClickImageCaptchaGenerator defaultImageCaptchaResourceManager =
new StandardClickImageCaptchaGenerator(imageCaptchaResourceManager, true);
GenerateParam generateParam = new GenerateParam();
generateParam.setType(CaptchaTypeConstant.WORD_CLICK);
ImageCaptchaInfo imageCaptchaInfo = defaultImageCaptchaResourceManager.generateCaptchaImage(generateParam);
}
}