mirror of
https://github.com/dromara/tianai-captcha.git
synced 2026-05-07 06:04:34 +08:00
添加点选验证码 点选文字验证码完成
This commit is contained in:
+3
-3
@@ -1,4 +1,4 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.common.constant;
|
||||
package cloud.tianai.captcha.template.slider.common.constant;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
@@ -13,6 +13,6 @@ public interface CaptchaTypeConstant {
|
||||
String ROTATE = "ROTATE";
|
||||
/** 拼接.*/
|
||||
String CONCAT = "CONCAT";
|
||||
/** 文字点选.*/
|
||||
String WORD_CLICK = "WORD_CLICK";
|
||||
/** 图片点选.*/
|
||||
String IMAGE_CLICK = "IMAGE_CLICK";
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package cloud.tianai.captcha.template.slider.common.util;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2022/4/28 17:03
|
||||
* @Description 验证码工具包
|
||||
*/
|
||||
public class CaptchaUtils {
|
||||
|
||||
/**
|
||||
* 是否是滑动验证码
|
||||
* @param type 类型
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isSliderCaptcha(String type) {
|
||||
return CaptchaTypeConstant.SLIDER.equals(type)
|
||||
|| CaptchaTypeConstant.ROTATE.equals(type)
|
||||
|| CaptchaTypeConstant.CONCAT.equals(type);
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否是点击验证码
|
||||
* @param type type
|
||||
* @return boolean
|
||||
*/
|
||||
public static boolean isClickCaptcha(String type) {
|
||||
return CaptchaTypeConstant.IMAGE_CLICK.equals(type);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
package cloud.tianai.captcha.template.slider.common.util;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import java.awt.*;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2022/4/27 11:34
|
||||
@@ -7,11 +13,17 @@ package cloud.tianai.captcha.template.slider.common.util;
|
||||
*/
|
||||
public class FontUtils {
|
||||
|
||||
public static char getRandomChar() {
|
||||
return (char)(0x4e00 + (int)(Math.random()*(0x9fa5 - 0x4e00 + 1)));
|
||||
@SneakyThrows
|
||||
public static String getRandomChar(Random random) {
|
||||
Integer hightPos, lowPos; // 定义高低位
|
||||
hightPos = (176 + Math.abs(random.nextInt(39)));
|
||||
lowPos = (161 + Math.abs(random.nextInt(93)));
|
||||
byte[] bytes = new byte[2];
|
||||
bytes[0] = hightPos.byteValue();
|
||||
bytes[1] = lowPos.byteValue();
|
||||
return new String(bytes, "GBK");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package cloud.tianai.captcha.template.slider.generator;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.template.slider.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.resource.ImageCaptchaResourceManager;
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2022/4/28 16:51
|
||||
* @Description 点击图片校验描述
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ClickImageCheckDefinition {
|
||||
/** 提示.*/
|
||||
private String tip;
|
||||
/** x.*/
|
||||
private Integer x;
|
||||
/** y.*/
|
||||
private Integer y;
|
||||
/** 宽.*/
|
||||
private Integer width;
|
||||
/** 高.*/
|
||||
private Integer height;
|
||||
|
||||
}
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
@@ -19,7 +19,7 @@ public class RotateImageCaptchaInfo extends ImageCaptchaInfo {
|
||||
*/
|
||||
private Double degree;
|
||||
/** 旋转图片的容错值大一点. */
|
||||
public static final Float DEFAULT_TOLERANT = 0.05F;
|
||||
public static final Float DEFAULT_TOLERANT = 0.03F;
|
||||
|
||||
public static RotateImageCaptchaInfo of(Double degree,
|
||||
Integer randomX,
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
-31
@@ -1,31 +0,0 @@
|
||||
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;
|
||||
|
||||
}
|
||||
}
|
||||
+146
-2
@@ -1,10 +1,13 @@
|
||||
package cloud.tianai.captcha.template.slider.common.util;
|
||||
package cloud.tianai.captcha.template.slider.generator.common.util;
|
||||
|
||||
import lombok.SneakyThrows;
|
||||
import sun.font.FontDesignMetrics;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.geom.Area;
|
||||
import java.awt.geom.CubicCurve2D;
|
||||
import java.awt.geom.QuadCurve2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.awt.image.ColorModel;
|
||||
import java.awt.image.PixelGrabber;
|
||||
@@ -12,6 +15,8 @@ import java.awt.image.WritableRaster;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Random;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
@@ -314,7 +319,146 @@ public class CaptchaImageUtils {
|
||||
}
|
||||
|
||||
public static char getRandomChar() {
|
||||
return (char)(0x4e00 + (int)(Math.random()*(0x9fa5 - 0x4e00 + 1)));
|
||||
return (char) (0x4e00 + (int) (Math.random() * (0x9fa5 - 0x4e00 + 1)));
|
||||
}
|
||||
|
||||
|
||||
@SneakyThrows
|
||||
public static BufferedImage drawWordImg(Color fontColor,
|
||||
String word,
|
||||
Font font,
|
||||
FontDesignMetrics metrics,
|
||||
int imgWidth,
|
||||
int imgHeight,
|
||||
float deg) {
|
||||
BufferedImage fillRect = new BufferedImage(imgWidth, imgHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = fillRect.createGraphics();
|
||||
g.setColor(new Color(255, 255, 255, 0));
|
||||
g.fillRect(0, 0, imgWidth, imgHeight);
|
||||
g.setColor(fontColor);
|
||||
g.setFont(font);
|
||||
float left = (imgWidth - font.getSize()) / 2f;
|
||||
float top = (imgHeight - font.getSize()) / 2f + metrics.getAscent() - 6;
|
||||
g.rotate(Math.toRadians(deg), imgWidth / 2f, imgHeight / 2f);
|
||||
g.drawString(word, left, top);
|
||||
g.dispose();
|
||||
return fillRect;
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机画干扰圆
|
||||
*
|
||||
* @param num 数量
|
||||
* @param color 颜色
|
||||
* @param g Graphics2D
|
||||
*/
|
||||
public static void drawOval(int num,
|
||||
Color color,
|
||||
Graphics2D g,
|
||||
int width,
|
||||
int height,
|
||||
Random random) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
g.setColor(color == null ? getRandomColor(random) : color);
|
||||
int w = 5 + random.nextInt(10);
|
||||
int x = random.nextInt(width - 25);
|
||||
int y = random.nextInt(height - 25);
|
||||
g.drawOval(x, y, w, w);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 随机画贝塞尔曲线
|
||||
*
|
||||
* @param num 数量
|
||||
* @param color 颜色
|
||||
* @param g Graphics2D
|
||||
*/
|
||||
public static void drawBesselLine(int num, Color color,
|
||||
Graphics2D g,
|
||||
int width,
|
||||
int height,
|
||||
ThreadLocalRandom random) {
|
||||
for (int i = 0; i < num; i++) {
|
||||
g.setColor(color == null ? getRandomColor(random) : color);
|
||||
int x1 = 5, y1 = random.nextInt(5, height / 2);
|
||||
int x2 = width - 5, y2 = random.nextInt(height / 2, height - 5);
|
||||
int ctrlx = random.nextInt(width / 4, width / 4 * 3);
|
||||
int ctrly = random.nextInt(5, height - 5);
|
||||
if (random.nextInt(2) == 0) {
|
||||
int ty = y1;
|
||||
y1 = y2;
|
||||
y2 = ty;
|
||||
}
|
||||
if (random.nextInt(2) == 0) { // 二阶贝塞尔曲线
|
||||
QuadCurve2D shape = new QuadCurve2D.Double();
|
||||
shape.setCurve(x1, y1, ctrlx, ctrly, x2, y2);
|
||||
g.draw(shape);
|
||||
} else { // 三阶贝塞尔曲线
|
||||
int ctrlx1 = random.nextInt(width / 4, width / 4 * 3);
|
||||
int ctrly1 = random.nextInt(5, height - 5);
|
||||
CubicCurve2D shape = new CubicCurve2D.Double(x1, y1, ctrlx, ctrly, ctrlx1, ctrly1, x2, y2);
|
||||
g.draw(shape);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成简单的验证码图片
|
||||
* @param data 验证码内容
|
||||
* @param font 字体包
|
||||
* @param metrics FontDesignMetrics
|
||||
* @param width 验证码宽度
|
||||
* @param height 验证码高度
|
||||
* @param startX 起始X
|
||||
* @param startY 起始Y
|
||||
* @param interferenceLineNum 干扰线数量
|
||||
* @param interferencePointNum 干扰点数量
|
||||
* @return BufferedImage
|
||||
*/
|
||||
public static BufferedImage genSimpleImgCaptcha(String data,
|
||||
Font font,
|
||||
FontDesignMetrics metrics,
|
||||
int width,
|
||||
int height,
|
||||
float startX,
|
||||
float startY,
|
||||
int interferenceLineNum,
|
||||
int interferencePointNum) {
|
||||
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = bufferedImage.createGraphics();
|
||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||
g.setFont(font);
|
||||
char[] chars = data.toCharArray();
|
||||
|
||||
for (int i = 0; i < chars.length; i++) {
|
||||
g.setColor(getRandomColor(random));
|
||||
g.drawString(String.valueOf(chars[i]), startX + i * font.getSize(), startY);
|
||||
}
|
||||
// 干扰点
|
||||
if (interferencePointNum > 0) {
|
||||
drawOval(interferencePointNum, null, g, width, height, random);
|
||||
}
|
||||
if (interferencePointNum > 0) {
|
||||
g.setStroke(new BasicStroke(1.2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
|
||||
// 干扰线
|
||||
drawBesselLine(interferenceLineNum, null, g, width, height, random);
|
||||
}
|
||||
return bufferedImage;
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机获取颜色
|
||||
* @return Color
|
||||
*/
|
||||
public static Color getRandomColor(Random random) {
|
||||
return new Color(
|
||||
random.nextInt(255),
|
||||
random.nextInt(255),
|
||||
random.nextInt(255));
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.generator.common.util.CaptchaImageUtils;
|
||||
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
||||
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ClickImageCheckDefinition;
|
||||
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.resource.common.model.dto.Resource;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
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.generator.common.util.CaptchaImageUtils.wrapFile2BufferedImage;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2022/4/27 11:46
|
||||
* @Description 点选验证码 点选验证码分为点选文字和点选图标等
|
||||
*/
|
||||
@Data
|
||||
public abstract class AbstractClickImageCaptchaGenerator extends AbstractImageCaptchaGenerator {
|
||||
|
||||
/** 参与校验的数量.*/
|
||||
protected Integer checkClickCount = 4;
|
||||
/** 干扰数量.*/
|
||||
protected Integer interferenceCount = 2;
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) {
|
||||
// 文字点选验证码不需要模板 只需要背景图
|
||||
Collection<InputStream> inputStreams = new LinkedList<>();
|
||||
try {
|
||||
Resource resourceImage = getImageResourceManager().randomGetResource(param.getType());
|
||||
InputStream resourceInputStream = getImageResourceManager().getResourceInputStream(resourceImage);
|
||||
inputStreams.add(resourceInputStream);
|
||||
BufferedImage bgImage = wrapFile2BufferedImage(resourceInputStream);
|
||||
|
||||
List<ClickImageCheckDefinition> clickImageCheckDefinitionList = new ArrayList<>(interferenceCount);
|
||||
int allImages = interferenceCount + checkClickCount;
|
||||
for (int i = 0; i < allImages; i++) {
|
||||
// 随机获取点击图片
|
||||
ImgWrapper imgWrapper = randomGetClickImg();
|
||||
BufferedImage image = imgWrapper.getImage();
|
||||
int clickImgWidth = image.getWidth();
|
||||
int clickImgHeight = image.getHeight();
|
||||
// 随机x
|
||||
int randomX = ThreadLocalRandom.current().nextInt(10, bgImage.getWidth() - clickImgWidth);
|
||||
// 随机y
|
||||
int randomY = ThreadLocalRandom.current().nextInt(10, bgImage.getHeight() - clickImgHeight);
|
||||
// 通过随机x和y 进行覆盖图片
|
||||
CaptchaImageUtils.overlayImage(bgImage, imgWrapper.getImage(), randomX, randomY);
|
||||
ImageIO.write(imgWrapper.getImage(), "png", new FileOutputStream("C:\\Users\\tianai\\Desktop\\111\\" + i + ".png"));
|
||||
ClickImageCheckDefinition clickImageCheckDefinition = new ClickImageCheckDefinition();
|
||||
clickImageCheckDefinition.setTip(imgWrapper.getTip());
|
||||
clickImageCheckDefinition.setX(randomX + clickImgWidth / 2);
|
||||
clickImageCheckDefinition.setY(randomY + clickImgHeight / 2);
|
||||
clickImageCheckDefinition.setWidth(clickImgWidth);
|
||||
clickImageCheckDefinition.setHeight(clickImgHeight);
|
||||
clickImageCheckDefinitionList.add(clickImageCheckDefinition);
|
||||
}
|
||||
// 背景图转换为字符串
|
||||
// String bgImageStr = transform(bgImage, param.getBackgroundFormatName());
|
||||
try {
|
||||
ImageIO.write(bgImage, "jpeg", new FileOutputStream("C:\\Users\\tianai\\Desktop\\123.jpg"));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
// 打乱
|
||||
Collections.shuffle(clickImageCheckDefinitionList);
|
||||
// 拿出参与校验的数据
|
||||
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList = new ArrayList<>(checkClickCount);
|
||||
for (int i = 0; i < checkClickCount; i++) {
|
||||
ClickImageCheckDefinition clickImageCheckDefinition = clickImageCheckDefinitionList.get(i);
|
||||
checkClickImageCheckDefinitionList.add(clickImageCheckDefinition);
|
||||
}
|
||||
// 将校验的文字生成提示图片
|
||||
ImgWrapper tipImage = genTipImage(checkClickImageCheckDefinitionList);
|
||||
|
||||
try {
|
||||
ImageIO.write(tipImage.getImage(), "png", new FileOutputStream("C:\\Users\\tianai\\Desktop\\456.png"));
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return wrapClickImageCaptchaInfo(param, bgImage, tipImage.getImage(), checkClickImageCheckDefinitionList);
|
||||
|
||||
} finally {
|
||||
// 使用完后关闭流
|
||||
for (InputStream inputStream : inputStreams) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// return null;
|
||||
}
|
||||
|
||||
protected ImageCaptchaInfo wrapClickImageCaptchaInfo(GenerateParam param, BufferedImage bgImage,
|
||||
BufferedImage tipImage,
|
||||
List<ClickImageCheckDefinition> checkClickImageCheckDefinitionList) {
|
||||
ImageCaptchaInfo clickImageCaptchaInfo = new ImageCaptchaInfo();
|
||||
clickImageCaptchaInfo.setBackgroundImage(transform(bgImage, param.getBackgroundFormatName()));
|
||||
clickImageCaptchaInfo.setSliderImage(transform(bgImage, param.getSliderFormatName()));
|
||||
clickImageCaptchaInfo.setBgImageWidth(bgImage.getWidth());
|
||||
clickImageCaptchaInfo.setBgImageHeight(bgImage.getHeight());
|
||||
clickImageCaptchaInfo.setSliderImageWidth(tipImage.getWidth());
|
||||
clickImageCaptchaInfo.setSliderImageHeight(tipImage.getHeight());
|
||||
clickImageCaptchaInfo.setRandomX(null);
|
||||
clickImageCaptchaInfo.setTolerant(null);
|
||||
clickImageCaptchaInfo.setType(CaptchaTypeConstant.IMAGE_CLICK);
|
||||
clickImageCaptchaInfo.setExpand(checkClickImageCheckDefinitionList);
|
||||
return clickImageCaptchaInfo;
|
||||
}
|
||||
|
||||
protected abstract ImgWrapper genTipImage(List<ClickImageCheckDefinition> imageCheckDefinitions);
|
||||
|
||||
protected abstract ImgWrapper randomGetClickImg();
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2022/4/28 14:26
|
||||
* @Description 点击图片包装
|
||||
*/
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public static class ImgWrapper {
|
||||
/** 图片.*/
|
||||
private BufferedImage image;
|
||||
/** 提示.*/
|
||||
private String tip;
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -3,7 +3,7 @@ package cloud.tianai.captcha.template.slider.generator.impl;
|
||||
import cloud.tianai.captcha.template.slider.common.util.ObjectUtils;
|
||||
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
||||
import cloud.tianai.captcha.template.slider.generator.ImageCaptchaGenerator;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.template.slider.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.resource.ImageCaptchaResourceManager;
|
||||
|
||||
-217
@@ -1,217 +0,0 @@
|
||||
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"));
|
||||
}
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.template.slider.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.resource.ImageCaptchaResourceManager;
|
||||
@@ -17,7 +17,7 @@ import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import static cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils.*;
|
||||
import static cloud.tianai.captcha.template.slider.generator.common.util.CaptchaImageUtils.*;
|
||||
import static cloud.tianai.captcha.template.slider.generator.impl.StandardSliderImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_RESOURCE_PATH;
|
||||
|
||||
/**
|
||||
|
||||
+115
@@ -0,0 +1,115 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.generator.common.util.CaptchaImageUtils;
|
||||
import cloud.tianai.captcha.template.slider.common.util.FontUtils;
|
||||
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ClickImageCheckDefinition;
|
||||
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 lombok.Data;
|
||||
import lombok.SneakyThrows;
|
||||
import sun.font.FontDesignMetrics;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
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 StandardRandomWordClickImageCaptchaGenerator extends AbstractClickImageCaptchaGenerator {
|
||||
|
||||
protected ImageCaptchaResourceManager imageCaptchaResourceManager;
|
||||
/** 字体包.*/
|
||||
protected Font font;
|
||||
protected FontDesignMetrics metrics;
|
||||
protected Integer clickImgWidth = 60;
|
||||
protected Integer clickImgHeight = 60;
|
||||
protected int tipImageInterferenceLineNum = 2;
|
||||
protected int tipImageInterferencePointNum = 5;
|
||||
|
||||
@SneakyThrows
|
||||
public StandardRandomWordClickImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager, boolean initDefaultResource) {
|
||||
this.imageCaptchaResourceManager = imageCaptchaResourceManager;
|
||||
if (initDefaultResource) {
|
||||
initDefaultResource();
|
||||
}
|
||||
// 使用默认字体
|
||||
Resource fontResource = new Resource(null, "META-INF/fonts/SIMSUN.TTC");
|
||||
InputStream inputStream = new ClassPathResourceProvider().doGetResourceInputStream(fontResource);
|
||||
Font font = Font.createFont(Font.TRUETYPE_FONT, inputStream);
|
||||
font = font.deriveFont(Font.BOLD, 50);
|
||||
this.metrics = FontDesignMetrics.getMetrics(font);
|
||||
this.font = font;
|
||||
setClickImgHeight(60);
|
||||
setClickImgWidth(60);
|
||||
}
|
||||
|
||||
public StandardRandomWordClickImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager,
|
||||
boolean initDefaultResource,
|
||||
Font font) {
|
||||
this.imageCaptchaResourceManager = imageCaptchaResourceManager;
|
||||
this.font = font;
|
||||
this.metrics = FontDesignMetrics.getMetrics(font);
|
||||
setClickImgWidth(font.getSize() + 10);
|
||||
setClickImgHeight(font.getSize() + 10);
|
||||
if (initDefaultResource) {
|
||||
initDefaultResource();
|
||||
}
|
||||
}
|
||||
|
||||
public void initDefaultResource() {
|
||||
ResourceStore resourceStore = imageCaptchaResourceManager.getResourceStore();
|
||||
// 添加一些系统的资源文件
|
||||
resourceStore.addResource(CaptchaTypeConstant.IMAGE_CLICK, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ImgWrapper genTipImage(List<ClickImageCheckDefinition> imageCheckDefinitions) {
|
||||
String tips = imageCheckDefinitions.stream().map(ClickImageCheckDefinition::getTip).collect(Collectors.joining());
|
||||
// 生成随机颜色
|
||||
int fontWidth = metrics.stringWidth(tips);
|
||||
int width = fontWidth + 5;
|
||||
int height = metrics.getHeight() + 5;
|
||||
float left = (width - fontWidth) / 2f;
|
||||
float top = 5 / 2f + metrics.getAscent();
|
||||
BufferedImage bufferedImage = CaptchaImageUtils.genSimpleImgCaptcha(tips,
|
||||
font, metrics, width, height, left, top, tipImageInterferenceLineNum, tipImageInterferencePointNum);
|
||||
return new ImgWrapper(bufferedImage, tips);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ImgWrapper randomGetClickImg() {
|
||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||
// 随机文字
|
||||
String randomWord = FontUtils.getRandomChar(random);
|
||||
// 随机颜色
|
||||
Color randomColor = CaptchaImageUtils.getRandomColor(random);
|
||||
// 随机角度
|
||||
int randomDeg = ThreadLocalRandom.current().nextInt(0, 85);
|
||||
BufferedImage fontImage = CaptchaImageUtils.drawWordImg(randomColor,
|
||||
randomWord,
|
||||
font,
|
||||
this.metrics,
|
||||
clickImgWidth,
|
||||
clickImgHeight,
|
||||
randomDeg);
|
||||
return new ImgWrapper(fontImage, randomWord);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageCaptchaResourceManager getImageResourceManager() {
|
||||
return imageCaptchaResourceManager;
|
||||
}
|
||||
|
||||
}
|
||||
+3
-3
@@ -1,8 +1,8 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.util.CaptchaImageUtils;
|
||||
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.SliderCaptchaConstant;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||
@@ -25,7 +25,7 @@ import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import static cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils.*;
|
||||
import static cloud.tianai.captcha.template.slider.generator.common.util.CaptchaImageUtils.*;
|
||||
import static cloud.tianai.captcha.template.slider.generator.impl.StandardSliderImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_RESOURCE_PATH;
|
||||
import static cloud.tianai.captcha.template.slider.generator.impl.StandardSliderImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH;
|
||||
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.generator.AbstractImageCaptchaGenerator;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.SliderCaptchaConstant;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||
@@ -22,7 +22,7 @@ import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import static cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils.*;
|
||||
import static cloud.tianai.captcha.template.slider.generator.common.util.CaptchaImageUtils.*;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
|
||||
+4
-4
@@ -15,11 +15,11 @@ public interface ImageCaptchaValidator {
|
||||
/**
|
||||
* 计算滑块要背景图的百分比,基本校验
|
||||
*
|
||||
* @param x 凹槽的x轴
|
||||
* @param bgImageWidth 背景图片的宽度
|
||||
* @param pos 移动的位置
|
||||
* @param maxPos 最大可移动的位置
|
||||
* @return float
|
||||
*/
|
||||
float calcPercentage(int x, int bgImageWidth);
|
||||
float calcPercentage(Number pos, Number maxPos);
|
||||
|
||||
/**
|
||||
* 校验滑块百分比
|
||||
@@ -46,7 +46,7 @@ public interface ImageCaptchaValidator {
|
||||
* @param imageCaptchaInfo 生成的验证码数据
|
||||
* @return Map<String, Object>
|
||||
*/
|
||||
Map<String, Object> generateSliderCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo);
|
||||
Map<String, Object> generateImageCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo);
|
||||
|
||||
/**
|
||||
* 校验用户滑动滑块是否正确
|
||||
|
||||
+125
-27
@@ -1,8 +1,10 @@
|
||||
package cloud.tianai.captcha.template.slider.validator.impl;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.template.slider.common.util.CaptchaUtils;
|
||||
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.ClickImageCheckDefinition;
|
||||
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;
|
||||
@@ -40,8 +42,8 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public float calcPercentage(int x, int bgImageWidth) {
|
||||
return (float) x / bgImageWidth;
|
||||
public float calcPercentage(Number pos, Number maxPos) {
|
||||
return pos.floatValue() / maxPos.floatValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,9 +64,8 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> generateSliderCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo) {
|
||||
public Map<String, Object> generateImageCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo) {
|
||||
Map<String, Object> map = new HashMap<>(8);
|
||||
addPercentage(imageCaptchaInfo, map);
|
||||
// 容错值
|
||||
Float tolerant = imageCaptchaInfo.getTolerant();
|
||||
if (tolerant != null && tolerant > 0) {
|
||||
@@ -76,17 +77,58 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
||||
type = CaptchaTypeConstant.SLIDER;
|
||||
}
|
||||
map.put(TYPE_KEY, type);
|
||||
|
||||
return afterGenerateImageCaptchaValidData(map, imageCaptchaInfo, type);
|
||||
}
|
||||
|
||||
public Map<String, Object> afterGenerateImageCaptchaValidData(Map<String, Object> map,
|
||||
ImageCaptchaInfo imageCaptchaInfo,
|
||||
String type) {
|
||||
if (CaptchaUtils.isSliderCaptcha(type)) {
|
||||
// 滑动验证码
|
||||
addPercentage(imageCaptchaInfo, map);
|
||||
} else if (CaptchaUtils.isClickCaptcha(type)) {
|
||||
// 图片点选验证码
|
||||
Object expand = imageCaptchaInfo.getExpand();
|
||||
if (expand == null) {
|
||||
throw new IllegalArgumentException("点选验证码扩展数据转换为 List<ClickImageCheckDefinition> 失败, info=" + imageCaptchaInfo);
|
||||
}
|
||||
List<ClickImageCheckDefinition> clickImageCheckDefinitionList = null;
|
||||
try {
|
||||
clickImageCheckDefinitionList = (List<ClickImageCheckDefinition>) expand;
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException("点选验证码扩展数据转换为 List<ClickImageCheckDefinition> 失败, info=" + imageCaptchaInfo);
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < clickImageCheckDefinitionList.size(); i++) {
|
||||
ClickImageCheckDefinition definition = clickImageCheckDefinitionList.get(i);
|
||||
Integer x = definition.getX();
|
||||
Integer y = definition.getY();
|
||||
Integer width = imageCaptchaInfo.getBgImageWidth();
|
||||
Integer height = imageCaptchaInfo.getBgImageHeight();
|
||||
float vx = calcPercentage(x, width);
|
||||
float vy = calcPercentage(y, height);
|
||||
sb.append(vx).append(",").append(vy).append(";");
|
||||
if (i == 0 && !map.containsKey(TOLERANT_KEY)) {
|
||||
// 重新计算容错值
|
||||
float minLeft = calcPercentage(x - definition.getWidth() / 2f, width);
|
||||
float tolerant = vx - minLeft;
|
||||
map.put(TOLERANT_KEY, tolerant);
|
||||
}
|
||||
}
|
||||
// 添加点选验证
|
||||
map.put(PERCENTAGE_KEY, sb.toString());
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean valid(SliderCaptchaTrack sliderCaptchaTrack, Map<String, Object> sliderCaptchaValidData) {
|
||||
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) {
|
||||
// 没有背景图片宽度
|
||||
@@ -97,34 +139,90 @@ public class SimpleImageCaptchaValidator implements ImageCaptchaValidator {
|
||||
// 没有滑动轨迹
|
||||
return false;
|
||||
}
|
||||
return doValid(sliderCaptchaTrack, sliderCaptchaValidData, oriPercentage, tolerantData, type);
|
||||
return afterValid(sliderCaptchaTrack, sliderCaptchaValidData, 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(), sliderCaptchaTrack.getBgImageWidth());
|
||||
// 校验百分比
|
||||
return checkPercentage(calcPercentage, oriPercentage, tolerant);
|
||||
public boolean afterValid(SliderCaptchaTrack sliderCaptchaTrack,
|
||||
Map<String, Object> sliderCaptchaValidData,
|
||||
Float tolerant,
|
||||
String type) {
|
||||
if (CaptchaUtils.isSliderCaptcha(type)) {
|
||||
// 滑动类型验证码
|
||||
return doValidSliderCaptcha(sliderCaptchaTrack, sliderCaptchaValidData, tolerant, type);
|
||||
} else if (CaptchaUtils.isClickCaptcha(type)) {
|
||||
// 点选类型验证码
|
||||
return doValidClickCaptcha(sliderCaptchaTrack, sliderCaptchaValidData, tolerant, type);
|
||||
}
|
||||
// 不支持的类型
|
||||
log.warn("校验验证码警告, 不支持的验证码类型:{}, 请手动扩展 cloud.tianai.captcha.template.slider.validator.impl.SimpleImageCaptchaValidator.doValid 进行校验扩展", type);
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验点选验证码
|
||||
* @param sliderCaptchaTrack sliderCaptchaTrack
|
||||
* @param sliderCaptchaValidData sliderCaptchaValidData
|
||||
* @param tolerant tolerant
|
||||
* @param type type
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean doValidClickCaptcha(SliderCaptchaTrack sliderCaptchaTrack,
|
||||
Map<String, Object> sliderCaptchaValidData,
|
||||
Float tolerant,
|
||||
String type) {
|
||||
String validStr = getStringParam(PERCENTAGE_KEY, sliderCaptchaValidData, null);
|
||||
if (ObjectUtils.isEmpty(validStr)) {
|
||||
return false;
|
||||
}
|
||||
String[] splitArr = validStr.split(";");
|
||||
List<SliderCaptchaTrack.Track> trackList = sliderCaptchaTrack.getTrackList();
|
||||
if (trackList.size() != splitArr.length) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < splitArr.length; i++) {
|
||||
SliderCaptchaTrack.Track track = trackList.get(i);
|
||||
String posStr = splitArr[i];
|
||||
String[] posArr = posStr.split(",");
|
||||
float xPercentage = Float.parseFloat(posArr[0]);
|
||||
float yPercentage = Float.parseFloat(posArr[1]);
|
||||
|
||||
float calcXPercentage = calcPercentage(track.getX(), sliderCaptchaTrack.getBgImageWidth());
|
||||
float calcYPercentage = calcPercentage(track.getY(), sliderCaptchaTrack.getBgImageWidth());
|
||||
|
||||
if (!checkPercentage(calcXPercentage, xPercentage, tolerant)
|
||||
|| !checkPercentage(calcYPercentage, yPercentage, tolerant)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验滑动验证码
|
||||
* @param sliderCaptchaTrack sliderCaptchaTrack
|
||||
* @param sliderCaptchaValidData sliderCaptchaValidData
|
||||
* @param tolerant tolerant
|
||||
* @param type type
|
||||
* @return boolean
|
||||
*/
|
||||
public boolean doValidSliderCaptcha(SliderCaptchaTrack sliderCaptchaTrack,
|
||||
Map<String, Object> sliderCaptchaValidData,
|
||||
Float tolerant,
|
||||
String type) {
|
||||
Float oriPercentage = getFloatParam(PERCENTAGE_KEY, sliderCaptchaValidData);
|
||||
if (oriPercentage == null) {
|
||||
// 没读取到百分比
|
||||
return false;
|
||||
}
|
||||
List<SliderCaptchaTrack.Track> trackList = sliderCaptchaTrack.getTrackList();
|
||||
// 取最后一个滑动轨迹
|
||||
SliderCaptchaTrack.Track lastTrack = trackList.get(trackList.size() - 1);
|
||||
// 计算百分比
|
||||
float calcPercentage = calcPercentage(lastTrack.getX(), sliderCaptchaTrack.getBgImageWidth());
|
||||
// 校验百分比
|
||||
return checkPercentage(calcPercentage, oriPercentage, tolerant);
|
||||
}
|
||||
|
||||
protected Float getFloatParam(String key, Map<String, Object> sliderCaptchaValidData) {
|
||||
return getFloatParam(key, sliderCaptchaValidData, null);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package example;
|
||||
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class AnchorPoint implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2L;
|
||||
|
||||
|
||||
/**
|
||||
* 保持charImgWidth的最大值+1
|
||||
*/
|
||||
private Integer x_iv = 26;
|
||||
/**
|
||||
* 保持charImgHeight的最大值+1
|
||||
*/
|
||||
private Integer y_iv = 21;
|
||||
|
||||
private Integer x;
|
||||
private Integer y;
|
||||
|
||||
public AnchorPoint(){
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
}
|
||||
|
||||
|
||||
public AnchorPoint(Integer x, Integer y){
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
public Integer getX() {
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
public Integer getY() {
|
||||
return y;
|
||||
}
|
||||
|
||||
public void setX(Integer x) {
|
||||
this.x = x;
|
||||
}
|
||||
|
||||
public void setY(Integer y) {
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
AnchorPoint that = (AnchorPoint) o;
|
||||
|
||||
//当X位置小于偏移量进行判段Y轴的偏移量
|
||||
if(this.x+this.x_iv > that.getX() || this.x - this.x_iv < that.getX()){
|
||||
//当Y轴的偏移量符合安全距离 判断锚点有效
|
||||
if(this.y+this.y_iv < that.getY() || this.y-this.y_iv > that.getY()){
|
||||
return false;
|
||||
}
|
||||
}else{
|
||||
//两个对象的X点保持在偏移量之外无需比较Y轴位置,判定锚点有效
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DrawXInteger{" +
|
||||
"x=" + x +
|
||||
", y=" + y +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,250 @@
|
||||
package example;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
||||
import cloud.tianai.captcha.template.slider.resource.impl.provider.ClassPathResourceProvider;
|
||||
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.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* 绘制验证码
|
||||
*/
|
||||
public class DrawCaptchaUtil {
|
||||
|
||||
/**
|
||||
* 画布宽度
|
||||
*/
|
||||
private static int canvasWidth = 300;
|
||||
|
||||
/**
|
||||
* 画布高度
|
||||
*/
|
||||
private static int canvasHeight = 150;
|
||||
|
||||
|
||||
/**
|
||||
* 图片宽度
|
||||
*/
|
||||
private static int imgWidth = 300;
|
||||
|
||||
/**
|
||||
* 图片高度
|
||||
*/
|
||||
private static int imgHeight = 150;
|
||||
|
||||
/**
|
||||
* 图中字体数量
|
||||
*/
|
||||
private static int charNumber = 5;
|
||||
|
||||
/**
|
||||
* 字体大小
|
||||
*/
|
||||
private static int fontSize = 50;
|
||||
/**
|
||||
* 字体图片宽度
|
||||
*/
|
||||
private static int charImgWidth = 60;
|
||||
/**
|
||||
* 字体图片高度
|
||||
*/
|
||||
private static int charImgHeight = 60;
|
||||
|
||||
|
||||
/**
|
||||
* 绘制验证码图片
|
||||
* @param checkCode
|
||||
* @param bkDirPath
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
public static BufferedImage drawImg(LinkedHashMap<String, AnchorPoint> checkCode, String bkDirPath) throws IOException {
|
||||
|
||||
BufferedImage imgCanvas = new BufferedImage(canvasWidth, canvasHeight, BufferedImage.TYPE_INT_BGR);
|
||||
Graphics graphics = imgCanvas.getGraphics();
|
||||
|
||||
|
||||
//绘制图形
|
||||
// graphics.setColor(new Color(0,0,0,0));
|
||||
graphics.fillRect(0, 0, imgWidth, imgHeight);
|
||||
|
||||
File bkPath = randomBackGroundImage(bkDirPath);
|
||||
|
||||
BufferedImage read = ImageIO.read(Files.newInputStream(Paths.get(bkPath.getAbsolutePath())));
|
||||
graphics.drawImage(read, 0, 0, null, null);
|
||||
//绘制字体
|
||||
// graphics.setColor(getRandomColor());
|
||||
//随机在图片中生成5个绘制点每个绘制点半径能不能重叠
|
||||
Set<AnchorPoint> point = new HashSet<>();
|
||||
|
||||
addPoint(point);
|
||||
Object[] pointArr = point.toArray();
|
||||
List<String> charList = new ArrayList<>();
|
||||
for (int i = 0; i < charNumber; i++) {
|
||||
AnchorPoint p = (AnchorPoint) pointArr[i];
|
||||
graphics.drawImage(getCharImg(getRandomColor(), charList), p.getX(), p.getY(), null, null);
|
||||
|
||||
}
|
||||
//随机获取3个字符串作为校验对象
|
||||
Object[] charArr = charList.toArray();
|
||||
Random random = new Random();
|
||||
for (int i = 0; i < 3; i++) {
|
||||
int num = random.nextInt(pointArr.length - i);
|
||||
String key = (String) charArr[num];
|
||||
AnchorPoint value = (AnchorPoint) pointArr[num];
|
||||
checkCode.put(key, value);
|
||||
//置换位置
|
||||
Object a = pointArr[num];
|
||||
pointArr[num] = pointArr[pointArr.length - 1 - i];
|
||||
pointArr[pointArr.length - 1 - i] = a;
|
||||
|
||||
a = charArr[num];
|
||||
charArr[num] = charArr[charArr.length - 1 - i];
|
||||
charArr[charArr.length - 1 - i] = a;
|
||||
}
|
||||
|
||||
return imgCanvas;
|
||||
}
|
||||
|
||||
/**
|
||||
* 在指定目录下随机获取背景图片
|
||||
* @param dir
|
||||
* @return
|
||||
*/
|
||||
private static File randomBackGroundImage(String dir) {
|
||||
File file = new File(dir);
|
||||
if (file.isDirectory()) {
|
||||
File[] files = file.listFiles();
|
||||
Random random = new Random();
|
||||
int i = random.nextInt(files.length);
|
||||
return files[i];
|
||||
} else {
|
||||
return file;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加坐标点
|
||||
* @param point
|
||||
*/
|
||||
private static void addPoint(Set<AnchorPoint> point) {
|
||||
Random random = new Random();
|
||||
//避免因为坐标点过于特殊导致无法获取下一个坐标点进入死循环,到100置空重新获取
|
||||
int clearNumber = 0;
|
||||
//生成前2个点坐标
|
||||
while (point.size() < 2) {
|
||||
|
||||
//添加X坐标点
|
||||
point.add(new AnchorPoint(random.nextInt(canvasWidth / 3), random.nextInt(canvasHeight - charImgWidth)));
|
||||
if (clearNumber == 100) {
|
||||
point.clear();
|
||||
clearNumber = 0;
|
||||
}
|
||||
clearNumber++;
|
||||
|
||||
}
|
||||
clearNumber = 0;
|
||||
//生成后3个点坐标
|
||||
while (point.size() < charNumber) {
|
||||
//添加X坐标点
|
||||
point.add(new AnchorPoint(random.nextInt(canvasWidth - charImgWidth), random.nextInt(canvasHeight - charImgHeight)));
|
||||
if (clearNumber == 100) {
|
||||
point.clear();
|
||||
clearNumber = 0;
|
||||
addPoint(point);
|
||||
break;
|
||||
}
|
||||
clearNumber++;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文字图片
|
||||
* @param fontColor
|
||||
* @param charList
|
||||
* @return
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
@SneakyThrows
|
||||
private static BufferedImage getCharImg(Color fontColor, List<String> charList) throws IOException {
|
||||
BufferedImage fillRect = new BufferedImage(charImgWidth, charImgHeight, BufferedImage.TYPE_INT_ARGB);
|
||||
Graphics2D g = fillRect.createGraphics();
|
||||
g.setColor(new Color(0, 0, 0, 0));
|
||||
g.fillRect(0, 0, charImgWidth, charImgHeight);
|
||||
g.setColor(fontColor);
|
||||
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, fontSize);
|
||||
// Font font = new Font("微软雅黑", Font.BOLD, fontSize);
|
||||
FontDesignMetrics metrics = FontDesignMetrics.getMetrics(font);
|
||||
// AffineTransform affineTransform = new AffineTransform();
|
||||
// affineTransform.rotate(Math.toRadians(85), 0, 0);
|
||||
// font.deriveFont(affineTransform);
|
||||
g.setFont(font);
|
||||
String charStr = getChineseCharacters();
|
||||
charList.add(charStr);
|
||||
|
||||
float left = (60 - 50) / 2f;
|
||||
// //顶边位置+上升距离(原本字体基线位置对准画布的y坐标导致字体偏上ascent距离,加上ascent后下移刚好顶边吻合)
|
||||
float top = (60 - 50) / 2f + metrics.getAscent() - 10;
|
||||
|
||||
g.rotate(Math.toRadians(ThreadLocalRandom.current().nextInt(0, 85)), 30, 30);
|
||||
g.drawString(charStr, left, top);
|
||||
g.dispose();
|
||||
return fillRect;
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机获取颜色
|
||||
* @return
|
||||
*/
|
||||
private static Color getRandomColor() {
|
||||
Random random = new Random();
|
||||
return new Color(
|
||||
random.nextInt(255),
|
||||
random.nextInt(255),
|
||||
random.nextInt(255));
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 随机获取中文字
|
||||
* @return
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
private static String getChineseCharacters() throws UnsupportedEncodingException {
|
||||
Integer hightPos, lowPos; // 定义高低位
|
||||
Random random = new Random();
|
||||
hightPos = (176 + Math.abs(random.nextInt(39)));
|
||||
lowPos = (161 + Math.abs(random.nextInt(93)));
|
||||
byte[] bytes = new byte[2];
|
||||
bytes[0] = hightPos.byteValue();
|
||||
bytes[1] = lowPos.byteValue();
|
||||
return new String(bytes, "GBK");
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
for (int i = 0; i < 100; i++) {
|
||||
BufferedImage charImg = getCharImg(getRandomColor(), new ArrayList<>());
|
||||
ImageIO.write(charImg, "png", new FileOutputStream("C:\\Users\\tianai\\Desktop\\111\\" + i + ".png"));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
package example;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.generator.ImageCaptchaGenerator;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.template.slider.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.RotateImageCaptchaInfo;
|
||||
import cloud.tianai.captcha.template.slider.generator.impl.CacheImageCaptchaGenerator;
|
||||
|
||||
@@ -1,23 +1,33 @@
|
||||
package example;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
|
||||
import cloud.tianai.captcha.template.slider.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.generator.impl.StandardRandomWordClickImageCaptchaGenerator;
|
||||
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
|
||||
import cloud.tianai.captcha.template.slider.resource.impl.DefaultImageCaptchaResourceManager;
|
||||
import cloud.tianai.captcha.template.slider.validator.impl.BasicCaptchaTrackValidator;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class StandardWordClickImageCaptchaGeneratorTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
ImageCaptchaResourceManager imageCaptchaResourceManager = new DefaultImageCaptchaResourceManager();
|
||||
|
||||
StandardClickImageCaptchaGenerator defaultImageCaptchaResourceManager =
|
||||
new StandardClickImageCaptchaGenerator(imageCaptchaResourceManager, true);
|
||||
StandardRandomWordClickImageCaptchaGenerator defaultImageCaptchaResourceManager =
|
||||
new StandardRandomWordClickImageCaptchaGenerator(imageCaptchaResourceManager, true);
|
||||
|
||||
GenerateParam generateParam = new GenerateParam();
|
||||
generateParam.setType(CaptchaTypeConstant.WORD_CLICK);
|
||||
generateParam.setType(CaptchaTypeConstant.IMAGE_CLICK);
|
||||
generateParam.setSliderFormatName("png");
|
||||
ImageCaptchaInfo imageCaptchaInfo = defaultImageCaptchaResourceManager.generateCaptchaImage(generateParam);
|
||||
|
||||
BasicCaptchaTrackValidator basicCaptchaTrackValidator = new BasicCaptchaTrackValidator();
|
||||
Map<String, Object> stringObjectMap = basicCaptchaTrackValidator.generateImageCaptchaValidData(imageCaptchaInfo);
|
||||
|
||||
System.out.println(stringObjectMap);
|
||||
|
||||
System.out.println(imageCaptchaInfo);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user