加入旋转图片验证码

This commit is contained in:
天爱有情
2022-04-24 13:21:53 +08:00
parent aa8f774551
commit bf971e2d9f
14 changed files with 205 additions and 115 deletions
+1 -1
View File
@@ -4,7 +4,7 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>cloud.tianai.captcha</groupId> <groupId>cloud.tianai.captcha</groupId>
<artifactId>tianai-captcha</artifactId> <artifactId>tianai-captcha</artifactId>
<version>1.3.0.RELEASE</version> <version>1.3.1.alpha</version>
<name>tianai-captcha</name> <name>tianai-captcha</name>
<description>滑块验证码</description> <description>滑块验证码</description>
+17 -17
View File
@@ -34,15 +34,15 @@
### 2. 使用 `SliderCaptchaGenerator`生成器生成滑块验证码 ### 2. 使用 `SliderCaptchaGenerator`生成器生成滑块验证码
```java ```java
import cloud.tianai.captcha.template.slider.generator.impl.StandardImageCaptchaGenerator; import cloud.tianai.captcha.template.slider.generator.impl.StandardSliderImageCaptchaGenerator;
import cloud.tianai.captcha.template.slider.generator.impl.StandardSliderCaptchaGenerator; import cloud.tianai.captcha.template.slider.generator.impl.StandardSliderCaptchaGenerator;
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager; import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
import cloud.tianai.captcha.template.slider.resource.impl.DefaultSliderCaptchaResourceManager; import cloud.tianai.captcha.template.slider.resource.impl.DefaultImageCaptchaResourceManager;
public class Test { public class Test {
public static void main(String[] args) throws InterruptedException { public static void main(String[] args) throws InterruptedException {
SliderCaptchaResourceManager sliderCaptchaResourceManager = new DefaultSliderCaptchaResourceManager(); ImageCaptchaResourceManager imageCaptchaResourceManager = new DefaultImageCaptchaResourceManager();
StandardImageCaptchaGenerator sliderCaptchaGenerator = new StandardImageCaptchaGenerator(sliderCaptchaResourceManager, true); StandardSliderImageCaptchaGenerator sliderCaptchaGenerator = new StandardSliderImageCaptchaGenerator(imageCaptchaResourceManager, true);
// 生成滑块图片 // 生成滑块图片
SliderCaptchaInfo slideImageInfo = sliderCaptchaGenerator.generateCaptchaImage(); SliderCaptchaInfo slideImageInfo = sliderCaptchaGenerator.generateCaptchaImage();
System.out.println(slideImageInfo); System.out.println(slideImageInfo);
@@ -101,9 +101,9 @@ public class Test2 {
public class Test { public class Test {
public static void main(String[] args) { public static void main(String[] args) {
// 资源管理器 // 资源管理器
SliderCaptchaResourceManager sliderCaptchaResourceManager = new DefaultSliderCaptchaResourceManager(); SliderCaptchaResourceManager imageCaptchaResourceManager = new DefaultSliderCaptchaResourceManager();
// 标准验证码生成器 // 标准验证码生成器
StandardSliderCaptchaGenerator sliderCaptchaGenerator = new StandardSliderCaptchaGenerator(sliderCaptchaResourceManager, true); StandardSliderCaptchaGenerator sliderCaptchaGenerator = new StandardSliderCaptchaGenerator(imageCaptchaResourceManager, true);
// 生成滑块图片 // 生成滑块图片
SliderCaptchaInfo slideImageInfo = sliderCaptchaGenerator.generateSlideImageInfo(GenerateParam.builder() SliderCaptchaInfo slideImageInfo = sliderCaptchaGenerator.generateSlideImageInfo(GenerateParam.builder()
.sliderFormatName("jpeg") .sliderFormatName("jpeg")
@@ -121,9 +121,9 @@ public class Test {
public class Test { public class Test {
public static void main(String[] args) { public static void main(String[] args) {
// 资源管理器 // 资源管理器
SliderCaptchaResourceManager sliderCaptchaResourceManager = new DefaultSliderCaptchaResourceManager(); SliderCaptchaResourceManager imageCaptchaResourceManager = new DefaultSliderCaptchaResourceManager();
// 标准验证码生成器 // 标准验证码生成器
StandardSliderCaptchaGenerator sliderCaptchaGenerator = new StandardSliderCaptchaGenerator(sliderCaptchaResourceManager, true); StandardSliderCaptchaGenerator sliderCaptchaGenerator = new StandardSliderCaptchaGenerator(imageCaptchaResourceManager, true);
// 生成滑块图片 // 生成滑块图片
SliderCaptchaInfo slideImageInfo = sliderCaptchaGenerator.generateSlideImageInfo(GenerateParam.builder() SliderCaptchaInfo slideImageInfo = sliderCaptchaGenerator.generateSlideImageInfo(GenerateParam.builder()
.sliderFormatName("webp") .sliderFormatName("webp")
@@ -143,7 +143,7 @@ public class Test {
public class Test { public class Test {
public static void main(String[] args) { public static void main(String[] args) {
// 通过资源管理器或者资源存储器 // 通过资源管理器或者资源存储器
ResourceStore resourceStore = sliderCaptchaResourceManager.getResourceStore(); ResourceStore resourceStore = imageCaptchaResourceManager.getResourceStore();
// 添加classpath目录下的 aa.jpg 图片 // 添加classpath目录下的 aa.jpg 图片
resourceStore.addResource(new Resource(ClassPathResourceProvider.NAME, "/aa.jpg")); resourceStore.addResource(new Resource(ClassPathResourceProvider.NAME, "/aa.jpg"));
// 添加远程url图片资源 // 添加远程url图片资源
@@ -165,7 +165,7 @@ public class Test {
public class Test { public class Test {
public static void main(String[] args) { public static void main(String[] args) {
// 通过资源管理器或者资源存储器 // 通过资源管理器或者资源存储器
ResourceStore resourceStore = sliderCaptchaResourceManager.getResourceStore(); ResourceStore resourceStore = imageCaptchaResourceManager.getResourceStore();
// 添加模板.模板图片由三张图片组成 // 添加模板.模板图片由三张图片组成
Map<String, Resource> template1 = new HashMap<>(4); Map<String, Resource> template1 = new HashMap<>(4);
template1.put(SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, "/active.png")); template1.put(SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, "/active.png"));
@@ -185,7 +185,7 @@ public class Test {
public static void main(String[] args) { public static void main(String[] args) {
//为方便快速上手 系统本身自带了一张图片和两套滑块模板,如果不想用系统自带的可以不让它加载系统自带的 //为方便快速上手 系统本身自带了一张图片和两套滑块模板,如果不想用系统自带的可以不让它加载系统自带的
// 第二个构造参数设置为false时将不加载默认的图片和模板 // 第二个构造参数设置为false时将不加载默认的图片和模板
SliderCaptchaGenerator sliderCaptchaGenerator = new StandardSliderCaptchaGenerator(sliderCaptchaResourceManager, false); SliderCaptchaGenerator sliderCaptchaGenerator = new StandardSliderCaptchaGenerator(imageCaptchaResourceManager, false);
} }
} }
``` ```
@@ -207,10 +207,10 @@ public class Test {
public class Test { public class Test {
public static void main(String[] args) { public static void main(String[] args) {
// 实现了 ResourceProvider 后 // 实现了 ResourceProvider 后
SliderCaptchaResourceManager sliderCaptchaResourceManager = new DefaultSliderCaptchaResourceManager(); SliderCaptchaResourceManager imageCaptchaResourceManager = new DefaultSliderCaptchaResourceManager();
StandardSliderCaptchaGenerator sliderCaptchaGenerator = new StandardSliderCaptchaGenerator(sliderCaptchaResourceManager, true); StandardSliderCaptchaGenerator sliderCaptchaGenerator = new StandardSliderCaptchaGenerator(imageCaptchaResourceManager, true);
// 注册 // 注册
sliderCaptchaResourceManager.registerResourceProvider(new CustomResourceProvider()); imageCaptchaResourceManager.registerResourceProvider(new CustomResourceProvider());
} }
} }
``` ```
@@ -227,8 +227,8 @@ public class Test {
// 参数二: 默认提前缓存多少个 // 参数二: 默认提前缓存多少个
// 参数三: 出错后 等待xx时间再进行生成 // 参数三: 出错后 等待xx时间再进行生成
// 参数四: 检查时间间隔 // 参数四: 检查时间间隔
SliderCaptchaResourceManager sliderCaptchaResourceManager = new DefaultSliderCaptchaResourceManager(); SliderCaptchaResourceManager imageCaptchaResourceManager = new DefaultSliderCaptchaResourceManager();
SliderCaptchaGenerator sliderCaptchaGenerator = new CacheSliderCaptchaGenerator(new StandardSliderCaptchaGenerator(sliderCaptchaResourceManager, true), 10, 1000, 100); SliderCaptchaGenerator sliderCaptchaGenerator = new CacheSliderCaptchaGenerator(new StandardSliderCaptchaGenerator(imageCaptchaResourceManager, true), 10, 1000, 100);
// 生成滑块图片 // 生成滑块图片
SliderCaptchaInfo slideImageInfo = sliderCaptchaGenerator.generateSlideImageInfo(); SliderCaptchaInfo slideImageInfo = sliderCaptchaGenerator.generateSlideImageInfo();
// 获取背景图片的base64 // 获取背景图片的base64
@@ -215,4 +215,14 @@ public class CaptchaImageUtils {
return img; return img;
} }
public static void centerOverlayAndRotateImage(BufferedImage baseBufferedImage, BufferedImage coverBufferedImage,
final double degree) {
coverBufferedImage = rotateImage(coverBufferedImage, degree);
int bw = baseBufferedImage.getWidth();
int bh = baseBufferedImage.getHeight();
int cw = coverBufferedImage.getWidth();
int ch = coverBufferedImage.getHeight();
overlayImage(baseBufferedImage, coverBufferedImage, bw / 2 - cw / 2, bh / 2 - ch / 2);
}
} }
@@ -14,7 +14,6 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Base64; import java.util.Base64;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
/** /**
* @Author: 天爱有情 * @Author: 天爱有情
@@ -71,7 +70,7 @@ public abstract class AbstractImageCaptchaGenerator implements ImageCaptchaGener
if (resource == null) { if (resource == null) {
throw new IllegalArgumentException("查找模板异常, 该模板下未找到 ".concat(imageName)); throw new IllegalArgumentException("查找模板异常, 该模板下未找到 ".concat(imageName));
} }
return getSlideImageResourceManager().getResourceInputStream(resource); return getImageResourceManager().getResourceInputStream(resource);
} }
} }
@@ -3,8 +3,7 @@ package cloud.tianai.captcha.template.slider.generator;
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant; 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.GenerateParam;
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo; import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager; import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
import cloud.tianai.captcha.template.slider.validator.SliderCaptchaValidator;
/** /**
* @Author: 天爱有情 * @Author: 天爱有情
@@ -45,6 +44,6 @@ public interface ImageCaptchaGenerator {
* *
* @return SliderCaptchaResourceManager * @return SliderCaptchaResourceManager
*/ */
SliderCaptchaResourceManager getSlideImageResourceManager(); ImageCaptchaResourceManager getImageResourceManager();
} }
@@ -1,9 +1,7 @@
package cloud.tianai.captcha.template.slider.generator.common.model.dto; package cloud.tianai.captcha.template.slider.generator.common.model.dto;
import lombok.AllArgsConstructor; import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
import lombok.Builder; import lombok.*;
import lombok.Data;
import lombok.NoArgsConstructor;
/** /**
* @Author: 天爱有情 * @Author: 天爱有情
@@ -14,6 +12,7 @@ import lombok.NoArgsConstructor;
@Builder @Builder
@NoArgsConstructor @NoArgsConstructor
@AllArgsConstructor @AllArgsConstructor
@EqualsAndHashCode
public class GenerateParam { public class GenerateParam {
/** 背景格式化名称.*/ /** 背景格式化名称.*/
private String backgroundFormatName = "jpeg"; private String backgroundFormatName = "jpeg";
@@ -22,5 +21,5 @@ public class GenerateParam {
/** 是否混淆.*/ /** 是否混淆.*/
private Boolean obfuscate = false; private Boolean obfuscate = false;
/** 类型.*/ /** 类型.*/
private String type; private String type = CaptchaTypeConstant.SLIDER;
} }
@@ -1,19 +1,17 @@
package cloud.tianai.captcha.template.slider.generator.impl; package cloud.tianai.captcha.template.slider.generator.impl;
import cloud.tianai.captcha.template.slider.common.util.NamedThreadFactory;
import cloud.tianai.captcha.template.slider.generator.ImageCaptchaGenerator; import cloud.tianai.captcha.template.slider.generator.ImageCaptchaGenerator;
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam; 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.ImageCaptchaInfo;
import cloud.tianai.captcha.template.slider.common.util.NamedThreadFactory; import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager;
import lombok.Getter; import lombok.Getter;
import lombok.Setter; import lombok.Setter;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import java.util.concurrent.ConcurrentLinkedQueue; import java.util.Map;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.*;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicInteger;
/** /**
@@ -25,29 +23,26 @@ import java.util.concurrent.atomic.AtomicInteger;
public class CacheImageCaptchaGenerator implements ImageCaptchaGenerator { public class CacheImageCaptchaGenerator implements ImageCaptchaGenerator {
protected final ScheduledExecutorService scheduledExecutor = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("slider-captcha-queue")); protected final ScheduledExecutorService scheduledExecutor = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("slider-captcha-queue"));
protected ConcurrentLinkedQueue<ImageCaptchaInfo> queue; protected Map<GenerateParam, ConcurrentLinkedQueue<ImageCaptchaInfo>> queueMap = new ConcurrentHashMap<>(8);
protected AtomicInteger pos = new AtomicInteger(0); protected Map<GenerateParam, AtomicInteger> posMap = new ConcurrentHashMap<>(8);
protected ImageCaptchaGenerator target; protected ImageCaptchaGenerator target;
protected int size; protected int size;
/** 等待时间,一般报错或者拉取为空时会休眠一段时间再试. */ /** 等待时间,一般报错或者拉取为空时会休眠一段时间再试. */
protected int waitTime = 1000; protected int waitTime = 1000;
/** 调度器检查缓存的间隔时间. */ /** 调度器检查缓存的间隔时间. */
protected int period = 100; protected int period = 100;
protected GenerateParam generateParam;
@Getter @Getter
@Setter @Setter
protected boolean requiredGetCaptcha = true; protected boolean requiredGetCaptcha = true;
public CacheImageCaptchaGenerator(ImageCaptchaGenerator target, GenerateParam generateParam, int size) { public CacheImageCaptchaGenerator(ImageCaptchaGenerator target, int size) {
this.target = target; this.target = target;
this.generateParam = generateParam;
this.size = size; this.size = size;
} }
public CacheImageCaptchaGenerator(ImageCaptchaGenerator target, GenerateParam generateParam, int size, int waitTime, int period) { public CacheImageCaptchaGenerator(ImageCaptchaGenerator target, int size, int waitTime, int period) {
this.target = target; this.target = target;
this.generateParam = generateParam;
this.size = size; this.size = size;
this.waitTime = waitTime; this.waitTime = waitTime;
this.period = period; this.period = period;
@@ -62,16 +57,16 @@ public class CacheImageCaptchaGenerator implements ImageCaptchaGenerator {
private void init(int z) { private void init(int z) {
this.size = z; this.size = z;
this.pos = new AtomicInteger(0);
queue = new ConcurrentLinkedQueue<>();
// 初始化一个队列扫描 // 初始化一个队列扫描
scheduledExecutor.scheduleAtFixedRate(() -> { scheduledExecutor.scheduleAtFixedRate(() -> {
queueMap.forEach((k, queue) -> {
try { try {
AtomicInteger pos = posMap.computeIfAbsent(k, k1 -> new AtomicInteger(0));
while (pos.get() < this.size) { while (pos.get() < this.size) {
if (pos.get() >= size) { if (pos.get() >= size) {
return; return;
} }
ImageCaptchaInfo slideImageInfo = target.generateCaptchaImage(generateParam); ImageCaptchaInfo slideImageInfo = target.generateCaptchaImage(k);
if (slideImageInfo != null) { if (slideImageInfo != null) {
boolean addStatus = queue.offer(slideImageInfo); boolean addStatus = queue.offer(slideImageInfo);
if (addStatus) { if (addStatus) {
@@ -88,8 +83,9 @@ public class CacheImageCaptchaGenerator implements ImageCaptchaGenerator {
// 休眠 // 休眠
sleep(); sleep();
} }
});
}, 0, period, TimeUnit.MILLISECONDS); }, 0, period, TimeUnit.MILLISECONDS);
log.info("缓存滑块验证码调度器初始化完成: size:{}, genParam:{}", size, generateParam);
} }
private void sleep() { private void sleep() {
@@ -102,11 +98,14 @@ public class CacheImageCaptchaGenerator implements ImageCaptchaGenerator {
@SneakyThrows @SneakyThrows
@Override @Override
public ImageCaptchaInfo generateCaptchaImage(String type) { public ImageCaptchaInfo generateCaptchaImage(String type) {
return generateCaptchaImage(this.requiredGetCaptcha); GenerateParam generateParam = new GenerateParam();
generateParam.setType(type);
return generateCaptchaImage(generateParam, this.requiredGetCaptcha);
} }
@SneakyThrows @SneakyThrows
public ImageCaptchaInfo generateCaptchaImage(boolean requiredGetCaptcha) { public ImageCaptchaInfo generateCaptchaImage(GenerateParam generateParam, boolean requiredGetCaptcha) {
ConcurrentLinkedQueue<ImageCaptchaInfo> queue = queueMap.computeIfAbsent(generateParam, g -> new ConcurrentLinkedQueue<>());
ImageCaptchaInfo poll = queue.poll(); ImageCaptchaInfo poll = queue.poll();
if (poll == null && requiredGetCaptcha) { if (poll == null && requiredGetCaptcha) {
log.warn("滑块验证码缓存不足, genParam:{}", generateParam); log.warn("滑块验证码缓存不足, genParam:{}", generateParam);
@@ -114,23 +113,32 @@ public class CacheImageCaptchaGenerator implements ImageCaptchaGenerator {
return target.generateCaptchaImage(generateParam); return target.generateCaptchaImage(generateParam);
} }
// 减1 // 减1
if (poll == null) {
AtomicInteger pos = posMap.get(generateParam);
if (pos != null) {
pos.decrementAndGet(); pos.decrementAndGet();
}
}
return poll; return poll;
} }
@Override @Override
public ImageCaptchaInfo generateCaptchaImage(String type, String targetFormatName, String matrixFormatName) { public ImageCaptchaInfo generateCaptchaImage(String type, String targetFormatName, String matrixFormatName) {
return target.generateCaptchaImage(type,targetFormatName, matrixFormatName); return generateCaptchaImage(GenerateParam.builder()
.type(type)
.backgroundFormatName(targetFormatName)
.sliderFormatName(matrixFormatName)
.build(), true);
} }
@Override @Override
public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) { public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) {
return target.generateCaptchaImage(param); return generateCaptchaImage(param, true);
} }
@Override @Override
public SliderCaptchaResourceManager getSlideImageResourceManager() { public ImageCaptchaResourceManager getImageResourceManager() {
return target.getSlideImageResourceManager(); return target.getImageResourceManager();
} }
@@ -0,0 +1,64 @@
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.generator.common.model.dto.GenerateParam;
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
import java.util.HashMap;
import java.util.Map;
/**
* @Author: 天爱有情
* @date 2022/4/24 9:27
* @Description 根据type 匹配对应的验证码生成器
*/
public class MultiImageCaptchaGenerator extends AbstractImageCaptchaGenerator {
private Map<String, ImageCaptchaGenerator> imageCaptchaGeneratorMap = new HashMap<>(4);
private ImageCaptchaResourceManager imageCaptchaResourceManager;
private boolean initDefaultResource;
private String defaultCaptcha = CaptchaTypeConstant.SLIDER;
public MultiImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager, boolean initDefaultResource) {
this.imageCaptchaResourceManager = imageCaptchaResourceManager;
this.initDefaultResource = initDefaultResource;
init();
}
protected void init() {
addImageCaptchaGenerator(CaptchaTypeConstant.SLIDER, new StandardSliderImageCaptchaGenerator(imageCaptchaResourceManager, initDefaultResource));
addImageCaptchaGenerator(CaptchaTypeConstant.ROTATE, new StandardRotateImageCaptchaGenerator(imageCaptchaResourceManager, initDefaultResource));
}
public void addImageCaptchaGenerator(String key, ImageCaptchaGenerator captchaGenerator) {
imageCaptchaGeneratorMap.put(key, captchaGenerator);
}
public ImageCaptchaGenerator removeImageCaptchaGenerator(String key) {
return imageCaptchaGeneratorMap.remove(key);
}
@Override
public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) {
String type = param.getType();
if (ObjectUtils.isEmpty(type)){
param.setType(defaultCaptcha);
type = defaultCaptcha;
}
ImageCaptchaGenerator imageCaptchaGenerator = imageCaptchaGeneratorMap.get(type);
if (imageCaptchaGenerator == null) {
throw new IllegalArgumentException("生成验证码失败,错误的type类型:" + type);
}
return imageCaptchaGenerator.generateCaptchaImage(param);
}
@Override
public ImageCaptchaResourceManager getImageResourceManager() {
return imageCaptchaResourceManager;
}
}
@@ -7,8 +7,8 @@ import cloud.tianai.captcha.template.slider.generator.common.constant.SliderCapt
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam; 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.ImageCaptchaInfo;
import cloud.tianai.captcha.template.slider.generator.common.model.dto.RotateImageCaptchaInfo; import cloud.tianai.captcha.template.slider.generator.common.model.dto.RotateImageCaptchaInfo;
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
import cloud.tianai.captcha.template.slider.resource.ResourceStore; import cloud.tianai.captcha.template.slider.resource.ResourceStore;
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager;
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource; 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.ClassPathResourceProvider;
import lombok.SneakyThrows; import lombok.SneakyThrows;
@@ -26,27 +26,27 @@ import java.util.Map;
import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.ThreadLocalRandom;
import static cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils.*; import static cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils.*;
import static cloud.tianai.captcha.template.slider.generator.impl.StandardImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_RESOURCE_PATH; import static cloud.tianai.captcha.template.slider.generator.impl.StandardSliderImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_RESOURCE_PATH;
import static cloud.tianai.captcha.template.slider.generator.impl.StandardImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH; import static cloud.tianai.captcha.template.slider.generator.impl.StandardSliderImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH;
/** /**
* @Author: 天爱有情 * @Author: 天爱有情
* @date 2022/4/22 16:43 * @date 2022/4/22 16:43
* @Description 旋转图片验证码生成器 * @Description 旋转图片验证码生成器
*/ */
public class StandardRotateCaptchaGenerator extends AbstractImageCaptchaGenerator { public class StandardRotateImageCaptchaGenerator extends AbstractImageCaptchaGenerator {
protected final SliderCaptchaResourceManager sliderCaptchaResourceManager; protected final ImageCaptchaResourceManager imageCaptchaResourceManager;
public StandardRotateCaptchaGenerator(SliderCaptchaResourceManager sliderCaptchaResourceManager, boolean initDefaultResource) { public StandardRotateImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager, boolean initDefaultResource) {
this.sliderCaptchaResourceManager = sliderCaptchaResourceManager; this.imageCaptchaResourceManager = imageCaptchaResourceManager;
if (initDefaultResource) { if (initDefaultResource) {
initDefaultResource(); initDefaultResource();
} }
} }
public void initDefaultResource() { public void initDefaultResource() {
ResourceStore resourceStore = sliderCaptchaResourceManager.getResourceStore(); ResourceStore resourceStore = imageCaptchaResourceManager.getResourceStore();
// 添加一些系统的资源文件 // 添加一些系统的资源文件
resourceStore.addResource(CaptchaTypeConstant.ROTATE, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg"))); resourceStore.addResource(CaptchaTypeConstant.ROTATE, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
@@ -54,6 +54,7 @@ public class StandardRotateCaptchaGenerator extends AbstractImageCaptchaGenerato
Map<String, Resource> template1 = new HashMap<>(4); Map<String, Resource> template1 = new HashMap<>(4);
template1.put(SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/3/active.png"))); template1.put(SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/3/active.png")));
template1.put(SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/3/fixed.png"))); template1.put(SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/3/fixed.png")));
template1.put(SliderCaptchaConstant.TEMPLATE_MATRIX_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/3/matrix.png")));
resourceStore.addTemplate(CaptchaTypeConstant.ROTATE, template1); resourceStore.addTemplate(CaptchaTypeConstant.ROTATE, template1);
} }
@@ -61,14 +62,14 @@ public class StandardRotateCaptchaGenerator extends AbstractImageCaptchaGenerato
public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) { public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) {
// 旋转验证码没有混淆 // 旋转验证码没有混淆
Boolean obfuscate = param.getObfuscate(); Boolean obfuscate = param.getObfuscate();
Map<String, Resource> templateImages = sliderCaptchaResourceManager.randomGetTemplate(param.getType()); Map<String, Resource> templateImages = imageCaptchaResourceManager.randomGetTemplate(param.getType());
if (templateImages == null || templateImages.isEmpty()) { if (templateImages == null || templateImages.isEmpty()) {
return null; return null;
} }
Collection<InputStream> inputStreams = new LinkedList<>(); Collection<InputStream> inputStreams = new LinkedList<>();
try { try {
Resource resourceImage = sliderCaptchaResourceManager.randomGetResource(param.getType()); Resource resourceImage = imageCaptchaResourceManager.randomGetResource(param.getType());
InputStream resourceInputStream = sliderCaptchaResourceManager.getResourceInputStream(resourceImage); InputStream resourceInputStream = imageCaptchaResourceManager.getResourceInputStream(resourceImage);
inputStreams.add(resourceInputStream); inputStreams.add(resourceInputStream);
BufferedImage cutBackground = wrapFile2BufferedImage(resourceInputStream); BufferedImage cutBackground = wrapFile2BufferedImage(resourceInputStream);
// 拷贝一份图片 // 拷贝一份图片
@@ -81,6 +82,11 @@ public class StandardRotateCaptchaGenerator extends AbstractImageCaptchaGenerato
InputStream activeTemplateInput = getTemplateFile(templateImages, SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME); InputStream activeTemplateInput = getTemplateFile(templateImages, SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME);
inputStreams.add(activeTemplateInput); inputStreams.add(activeTemplateInput);
BufferedImage activeTemplate = wrapFile2BufferedImage(activeTemplateInput); BufferedImage activeTemplate = wrapFile2BufferedImage(activeTemplateInput);
InputStream matrixTemplateInput = getTemplateFile(templateImages, SliderCaptchaConstant.TEMPLATE_MATRIX_IMAGE_NAME);
inputStreams.add(matrixTemplateInput);
BufferedImage matrixTemplate = wrapFile2BufferedImage(matrixTemplateInput);
// 算出居中的x和y // 算出居中的x和y
int x = targetBackground.getWidth() / 2 - fixedTemplate.getWidth() / 2; int x = targetBackground.getWidth() / 2 - fixedTemplate.getWidth() / 2;
int y = targetBackground.getHeight() / 2 - fixedTemplate.getHeight() / 2; int y = targetBackground.getHeight() / 2 - fixedTemplate.getHeight() / 2;
@@ -91,10 +97,10 @@ public class StandardRotateCaptchaGenerator extends AbstractImageCaptchaGenerato
// 随机旋转抠图部分 // 随机旋转抠图部分
// 随机x 转换为角度 // 随机x 转换为角度
int randomX = ThreadLocalRandom.current().nextInt(fixedTemplate.getWidth() + 10, targetBackground.getWidth() - 10); int randomX = ThreadLocalRandom.current().nextInt(fixedTemplate.getWidth() + 10, targetBackground.getWidth() - 10);
double degree = randomX / ((targetBackground.getWidth()) / 360d); double degree = 360d - randomX / ((targetBackground.getWidth()) / 360d);
// int degree = ThreadLocalRandom.current().nextInt(10, 350); // int degree = ThreadLocalRandom.current().nextInt(10, 350);
cutImage = rotateImage(cutImage, degree); centerOverlayAndRotateImage(matrixTemplate, cutImage, degree);
return wrapRotateCaptchaInfo(degree, randomX, targetBackground, cutImage, param); return wrapRotateCaptchaInfo(degree, randomX, targetBackground, matrixTemplate, param);
} finally { } finally {
// 使用完后关闭流 // 使用完后关闭流
for (InputStream inputStream : inputStreams) { for (InputStream inputStream : inputStreams) {
@@ -122,9 +128,19 @@ public class StandardRotateCaptchaGenerator extends AbstractImageCaptchaGenerato
); );
} }
// @Override
// public String transform(BufferedImage bufferedImage, String formatType) throws IOException {
// FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Thinkpad\\Desktop\\aa" + formatType + "." + formatType);
// ImageIO.write(bufferedImage, formatType, fileOutputStream);
// fileOutputStream.close();
//// return super.transform(bufferedImage, formatType);
// return "";
// }
@Override @Override
public SliderCaptchaResourceManager getSlideImageResourceManager() { public ImageCaptchaResourceManager getImageResourceManager() {
return sliderCaptchaResourceManager; return imageCaptchaResourceManager;
} }
public static void main(String[] args) throws IOException { public static void main(String[] args) throws IOException {
@@ -6,8 +6,8 @@ import cloud.tianai.captcha.template.slider.generator.common.constant.SliderCapt
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam; 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.ImageCaptchaInfo;
import cloud.tianai.captcha.template.slider.generator.common.model.dto.SliderImageCaptchaInfo; import cloud.tianai.captcha.template.slider.generator.common.model.dto.SliderImageCaptchaInfo;
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
import cloud.tianai.captcha.template.slider.resource.ResourceStore; import cloud.tianai.captcha.template.slider.resource.ResourceStore;
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager;
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource; 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.ClassPathResourceProvider;
import lombok.SneakyThrows; import lombok.SneakyThrows;
@@ -30,7 +30,7 @@ import static cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils
* @Description 滑块验证码模板 * @Description 滑块验证码模板
*/ */
@Slf4j @Slf4j
public class StandardImageCaptchaGenerator extends AbstractImageCaptchaGenerator { public class StandardSliderImageCaptchaGenerator extends AbstractImageCaptchaGenerator {
/** /**
* 默认的resource资源文件路径. * 默认的resource资源文件路径.
@@ -41,12 +41,12 @@ public class StandardImageCaptchaGenerator extends AbstractImageCaptchaGenerator
*/ */
public static final String DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH = "META-INF/cut-image/template"; public static final String DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH = "META-INF/cut-image/template";
protected final SliderCaptchaResourceManager sliderCaptchaResourceManager; protected final ImageCaptchaResourceManager imageCaptchaResourceManager;
public StandardImageCaptchaGenerator(SliderCaptchaResourceManager sliderCaptchaResourceManager, public StandardSliderImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager,
boolean initDefaultResource) { boolean initDefaultResource) {
this.sliderCaptchaResourceManager = sliderCaptchaResourceManager; this.imageCaptchaResourceManager = imageCaptchaResourceManager;
if (initDefaultResource) { if (initDefaultResource) {
initDefaultResource(); initDefaultResource();
} }
@@ -56,14 +56,14 @@ public class StandardImageCaptchaGenerator extends AbstractImageCaptchaGenerator
@Override @Override
public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) { public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) {
Boolean obfuscate = param.getObfuscate(); Boolean obfuscate = param.getObfuscate();
Map<String, Resource> templateImages = sliderCaptchaResourceManager.randomGetTemplate(param.getType()); Map<String, Resource> templateImages = imageCaptchaResourceManager.randomGetTemplate(param.getType());
if (templateImages == null || templateImages.isEmpty()) { if (templateImages == null || templateImages.isEmpty()) {
return null; return null;
} }
Collection<InputStream> inputStreams = new LinkedList<>(); Collection<InputStream> inputStreams = new LinkedList<>();
try { try {
Resource resourceImage = sliderCaptchaResourceManager.randomGetResource(param.getType()); Resource resourceImage = imageCaptchaResourceManager.randomGetResource(param.getType());
InputStream resourceInputStream = sliderCaptchaResourceManager.getResourceInputStream(resourceImage); InputStream resourceInputStream = imageCaptchaResourceManager.getResourceInputStream(resourceImage);
inputStreams.add(resourceInputStream); inputStreams.add(resourceInputStream);
BufferedImage cutBackground = wrapFile2BufferedImage(resourceInputStream); BufferedImage cutBackground = wrapFile2BufferedImage(resourceInputStream);
// 拷贝一份图片 // 拷贝一份图片
@@ -139,8 +139,8 @@ public class StandardImageCaptchaGenerator extends AbstractImageCaptchaGenerator
} }
@Override @Override
public SliderCaptchaResourceManager getSlideImageResourceManager() { public ImageCaptchaResourceManager getImageResourceManager() {
return sliderCaptchaResourceManager; return imageCaptchaResourceManager;
} }
protected int randomObfuscateX(int sliderX, int slWidth, int bgWidth) { protected int randomObfuscateX(int sliderX, int slWidth, int bgWidth) {
@@ -156,7 +156,7 @@ public class StandardImageCaptchaGenerator extends AbstractImageCaptchaGenerator
* 初始化默认资源 * 初始化默认资源
*/ */
public void initDefaultResource() { public void initDefaultResource() {
ResourceStore resourceStore = sliderCaptchaResourceManager.getResourceStore(); ResourceStore resourceStore = imageCaptchaResourceManager.getResourceStore();
// 添加一些系统的资源文件 // 添加一些系统的资源文件
resourceStore.addResource(CaptchaTypeConstant.SLIDER, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg"))); resourceStore.addResource(CaptchaTypeConstant.SLIDER, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
@@ -9,9 +9,9 @@ import java.util.Map;
/** /**
* @Author: 天爱有情 * @Author: 天爱有情
* @date 2021/8/7 15:26 * @date 2021/8/7 15:26
* @Description 滑块验证码图片资源管理器 * @Description 验证码图片资源管理器
*/ */
public interface SliderCaptchaResourceManager { public interface ImageCaptchaResourceManager {
/** /**
* 随机获取某个模板 * 随机获取某个模板
@@ -1,8 +1,8 @@
package cloud.tianai.captcha.template.slider.resource.impl; package cloud.tianai.captcha.template.slider.resource.impl;
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
import cloud.tianai.captcha.template.slider.resource.ResourceProvider; import cloud.tianai.captcha.template.slider.resource.ResourceProvider;
import cloud.tianai.captcha.template.slider.resource.ResourceStore; import cloud.tianai.captcha.template.slider.resource.ResourceStore;
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager;
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource; 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.ClassPathResourceProvider;
import cloud.tianai.captcha.template.slider.resource.impl.provider.FileResourceProvider; import cloud.tianai.captcha.template.slider.resource.impl.provider.FileResourceProvider;
@@ -19,18 +19,18 @@ import java.util.Map;
* @date 2021/8/7 15:35 * @date 2021/8/7 15:35
* @Description 默认的滑块验证码资源管理 * @Description 默认的滑块验证码资源管理
*/ */
public class DefaultSliderCaptchaResourceManager implements SliderCaptchaResourceManager { public class DefaultImageCaptchaResourceManager implements ImageCaptchaResourceManager {
private ResourceStore resourceStore; private ResourceStore resourceStore;
private List<ResourceProvider> resourceProviderList = new ArrayList<>(8); private List<ResourceProvider> resourceProviderList = new ArrayList<>(8);
public DefaultSliderCaptchaResourceManager() { public DefaultImageCaptchaResourceManager() {
init(); init();
} }
public DefaultSliderCaptchaResourceManager(ResourceStore resourceStore) { public DefaultImageCaptchaResourceManager(ResourceStore resourceStore) {
this.resourceStore = resourceStore; this.resourceStore = resourceStore;
init(); init();
} }
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

@@ -1,18 +1,13 @@
package example; package example;
import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant; import cloud.tianai.captcha.template.slider.generator.common.constant.CaptchaTypeConstant;
import cloud.tianai.captcha.template.slider.generator.common.constant.SliderCaptchaConstant;
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo; 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.common.model.dto.RotateImageCaptchaInfo;
import cloud.tianai.captcha.template.slider.generator.impl.StandardRotateCaptchaGenerator; import cloud.tianai.captcha.template.slider.generator.impl.StandardRotateImageCaptchaGenerator;
import cloud.tianai.captcha.template.slider.resource.ImageCaptchaResourceManager;
import cloud.tianai.captcha.template.slider.resource.ResourceStore; import cloud.tianai.captcha.template.slider.resource.ResourceStore;
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager; import cloud.tianai.captcha.template.slider.resource.impl.DefaultImageCaptchaResourceManager;
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
import cloud.tianai.captcha.template.slider.resource.impl.DefaultResourceStore; import cloud.tianai.captcha.template.slider.resource.impl.DefaultResourceStore;
import cloud.tianai.captcha.template.slider.resource.impl.DefaultSliderCaptchaResourceManager;
import java.util.HashMap;
import java.util.Map;
public class StandardRotateCaptchaGeneratorTest { public class StandardRotateCaptchaGeneratorTest {
@@ -25,10 +20,10 @@ public class StandardRotateCaptchaGeneratorTest {
// resourceStore.addTemplate(CaptchaTypeConstant.ROTATE, template); // resourceStore.addTemplate(CaptchaTypeConstant.ROTATE, template);
// resourceStore.addResource(CaptchaTypeConstant.ROTATE, new Resource("file", "E:\\projects\\tianai-captcha\\src\\main\\resources\\META-INF\\cut-image\\resource\\1.jpg")); // resourceStore.addResource(CaptchaTypeConstant.ROTATE, new Resource("file", "E:\\projects\\tianai-captcha\\src\\main\\resources\\META-INF\\cut-image\\resource\\1.jpg"));
SliderCaptchaResourceManager sliderCaptchaResourceManager = new DefaultSliderCaptchaResourceManager(resourceStore); ImageCaptchaResourceManager imageCaptchaResourceManager = new DefaultImageCaptchaResourceManager(resourceStore);
StandardRotateCaptchaGenerator standardRotateCaptchaGenerator = new StandardRotateCaptchaGenerator(sliderCaptchaResourceManager, true); StandardRotateImageCaptchaGenerator standardRotateImageCaptchaGenerator = new StandardRotateImageCaptchaGenerator(imageCaptchaResourceManager, true);
ImageCaptchaInfo imageCaptchaInfo = standardRotateCaptchaGenerator.generateCaptchaImage(CaptchaTypeConstant.ROTATE); ImageCaptchaInfo imageCaptchaInfo = standardRotateImageCaptchaGenerator.generateCaptchaImage(CaptchaTypeConstant.ROTATE);
System.out.println("backgroundImage:" + imageCaptchaInfo.getBackgroundImage()); System.out.println("backgroundImage:" + imageCaptchaInfo.getBackgroundImage());
System.out.println("sliderImage:" + imageCaptchaInfo.getSliderImage()); System.out.println("sliderImage:" + imageCaptchaInfo.getSliderImage());
System.out.println(((RotateImageCaptchaInfo)imageCaptchaInfo).getDegree()); System.out.println(((RotateImageCaptchaInfo)imageCaptchaInfo).getDegree());