mirror of
https://github.com/dromara/tianai-captcha.git
synced 2026-05-07 06:04:34 +08:00
旋转图片
This commit is contained in:
@@ -176,4 +176,43 @@ public class CaptchaImageUtils {
|
||||
}
|
||||
|
||||
|
||||
// /**
|
||||
// * 旋转图片
|
||||
// *
|
||||
// * @param bufferedImage 图片
|
||||
// * @param degree 旋转xx度
|
||||
// */
|
||||
// public static void rotateImage(BufferedImage bufferedImage, int degree) {
|
||||
// // 创建Graphics2D对象,用在底图对象上绘图
|
||||
// Graphics2D g2d = bufferedImage.createGraphics();
|
||||
// // 绘制
|
||||
// g2d.rotate(Math.toRadians(degree), bufferedImage.getWidth() / 2, bufferedImage.getHeight()/2);
|
||||
// g2d.drawImage(bufferedImage, 0, 0, bufferedImage.getWidth(), bufferedImage.getHeight(), null);
|
||||
// // 释放图形上下文使用的系统资源
|
||||
// g2d.dispose();
|
||||
// }
|
||||
|
||||
public static BufferedImage rotateImage(final BufferedImage bufferedimage,
|
||||
final double degree) {
|
||||
// 得到图片宽度。
|
||||
int w = bufferedimage.getWidth();
|
||||
// 得到图片高度。
|
||||
int h = bufferedimage.getHeight();
|
||||
// 得到图片透明度。
|
||||
int type = bufferedimage.getColorModel().getTransparency();
|
||||
BufferedImage img;// 空的图片。
|
||||
Graphics2D graphics2d;// 空的画笔。
|
||||
(graphics2d = (img = new BufferedImage(w, h, type))
|
||||
.createGraphics()).setRenderingHint(
|
||||
RenderingHints.KEY_INTERPOLATION,
|
||||
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
||||
// 旋转,degree是整型,度数,比如垂直90度。
|
||||
graphics2d.rotate(Math.toRadians(degree), w / 2, h / 2);
|
||||
// 从bufferedimagecopy图片至img,0,0是img的坐标。
|
||||
graphics2d.drawImage(bufferedimage, 0, 0, null);
|
||||
graphics2d.dispose();
|
||||
// 返回复制好的图片,原图片依然没有变,没有旋转,下次还可以使用。
|
||||
return img;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+77
@@ -0,0 +1,77 @@
|
||||
package cloud.tianai.captcha.template.slider.generator;
|
||||
|
||||
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.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Base64;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2022/4/22 16:30
|
||||
* @Description 抽象的验证码生成器
|
||||
*/
|
||||
public abstract class AbstractImageCaptchaGenerator implements ImageCaptchaGenerator {
|
||||
public static String DEFAULT_BG_IMAGE_TYPE = "jpeg";
|
||||
public static String DEFAULT_SLIDER_IMAGE_TYPE = "png";
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
/** 默认背景图片类型. */
|
||||
public String defaultBgImageType = DEFAULT_BG_IMAGE_TYPE;
|
||||
@Getter
|
||||
@Setter
|
||||
/** 默认滑块图片类型. */
|
||||
public String defaultSliderImageType = DEFAULT_SLIDER_IMAGE_TYPE;
|
||||
|
||||
@Override
|
||||
public ImageCaptchaInfo generateCaptchaImage(String type) {
|
||||
return generateCaptchaImage(type, defaultBgImageType, defaultSliderImageType);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public ImageCaptchaInfo generateCaptchaImage(String type, String backgroundFormatName, String sliderFormatName) {
|
||||
return generateCaptchaImage(GenerateParam.builder()
|
||||
.type(type)
|
||||
.backgroundFormatName(backgroundFormatName)
|
||||
.sliderFormatName(sliderFormatName)
|
||||
.obfuscate(false)
|
||||
.build());
|
||||
}
|
||||
|
||||
/**
|
||||
* 将图片转换成字符串格式
|
||||
*
|
||||
* @param bufferedImage 图片
|
||||
* @param formatType 格式化类型
|
||||
* @return String
|
||||
*/
|
||||
public String transform(BufferedImage bufferedImage, String formatType) throws IOException {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
ImageIO.write(bufferedImage, formatType, byteArrayOutputStream);
|
||||
//转换成字节码
|
||||
byte[] data = byteArrayOutputStream.toByteArray();
|
||||
String base64 = Base64.getEncoder().encodeToString(data);
|
||||
return "data:image/" + formatType + ";base64,".concat(base64);
|
||||
}
|
||||
|
||||
protected InputStream getTemplateFile(Map<String, Resource> templateImages, String imageName) {
|
||||
Resource resource = templateImages.get(imageName);
|
||||
if (resource == null) {
|
||||
throw new IllegalArgumentException("查找模板异常, 该模板下未找到 ".concat(imageName));
|
||||
}
|
||||
return getSlideImageResourceManager().getResourceInputStream(resource);
|
||||
}
|
||||
|
||||
}
|
||||
+11
-21
@@ -1,33 +1,35 @@
|
||||
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.model.dto.GenerateParam;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.SliderCaptchaInfo;
|
||||
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.validator.SliderCaptchaValidator;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2020/10/19 18:37
|
||||
* @Description 滑块验证码模板
|
||||
* @Description 图片验证码生成器
|
||||
*/
|
||||
public interface SliderCaptchaGenerator {
|
||||
public interface ImageCaptchaGenerator {
|
||||
|
||||
|
||||
/**
|
||||
* 获取滑块验证码
|
||||
*
|
||||
* 生成验证码图片
|
||||
* @param type 类型 {@link CaptchaTypeConstant}
|
||||
* @return SliderCaptchaInfo
|
||||
*/
|
||||
SliderCaptchaInfo generateSlideImageInfo();
|
||||
ImageCaptchaInfo generateCaptchaImage(String type);
|
||||
|
||||
|
||||
/**
|
||||
* 生成滑块验证码
|
||||
*
|
||||
* @param type type {@link CaptchaTypeConstant}
|
||||
* @param targetFormatName jpeg或者webp格式
|
||||
* @param matrixFormatName png或者webp格式
|
||||
* @return SliderCaptchaInfo
|
||||
*/
|
||||
SliderCaptchaInfo generateSlideImageInfo(String targetFormatName, String matrixFormatName);
|
||||
ImageCaptchaInfo generateCaptchaImage(String type, String targetFormatName, String matrixFormatName);
|
||||
|
||||
/**
|
||||
* 生成滑块验证码
|
||||
@@ -35,20 +37,8 @@ public interface SliderCaptchaGenerator {
|
||||
* @param param 生成参数
|
||||
* @return SliderCaptchaInfo
|
||||
*/
|
||||
SliderCaptchaInfo generateSlideImageInfo(GenerateParam param);
|
||||
ImageCaptchaInfo generateCaptchaImage(GenerateParam param);
|
||||
|
||||
/**
|
||||
* 百分比对比
|
||||
*
|
||||
* @param newPercentage 用户百分比
|
||||
* @param oriPercentage 原百分比
|
||||
* @return true 成功 false 失败
|
||||
* <p>
|
||||
* 废除 , 建议使用
|
||||
* @see SliderCaptchaValidator 进行校验
|
||||
*/
|
||||
@Deprecated
|
||||
boolean percentageContrast(Float newPercentage, Float oriPercentage);
|
||||
|
||||
/**
|
||||
* 获取滑块验证码资源管理器
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.common.constant;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2021/8/7 17:14
|
||||
* @Description 滑块类型
|
||||
*/
|
||||
public interface CaptchaTypeConstant {
|
||||
|
||||
/** 滑块. */
|
||||
String SLIDER = "SLIDER";
|
||||
/** 旋转. */
|
||||
String ROTATE = "ROTATE";
|
||||
}
|
||||
+2
@@ -21,4 +21,6 @@ public class GenerateParam {
|
||||
private String sliderFormatName = "png";
|
||||
/** 是否混淆.*/
|
||||
private Boolean obfuscate = false;
|
||||
/** 类型.*/
|
||||
private String type;
|
||||
}
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @Date 2020/5/29 8:04
|
||||
* @Description 滑块验证码
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class ImageCaptchaInfo {
|
||||
|
||||
/**
|
||||
* 背景图
|
||||
*/
|
||||
private String backgroundImage;
|
||||
/**
|
||||
* 移动图
|
||||
*/
|
||||
private String sliderImage;
|
||||
/** 背景图片宽度. */
|
||||
private Integer bgImageWidth;
|
||||
/** 背景图片高度. */
|
||||
private Integer bgImageHeight;
|
||||
/** 滑块图片宽度. */
|
||||
private Integer sliderImageWidth;
|
||||
/** 滑块图片高度. */
|
||||
private Integer sliderImageHeight;
|
||||
/** 随机值.*/
|
||||
private Integer randomX;
|
||||
/**
|
||||
* 扩展字段
|
||||
*/
|
||||
public Object expand;
|
||||
|
||||
public ImageCaptchaInfo(String backgroundImage,
|
||||
String sliderImage,
|
||||
Integer bgImageWidth,
|
||||
Integer bgImageHeight,
|
||||
Integer sliderImageWidth,
|
||||
Integer sliderImageHeight,
|
||||
Integer randomX) {
|
||||
this.backgroundImage = backgroundImage;
|
||||
this.sliderImage = sliderImage;
|
||||
this.bgImageWidth = bgImageWidth;
|
||||
this.bgImageHeight = bgImageHeight;
|
||||
this.sliderImageWidth = sliderImageWidth;
|
||||
this.sliderImageHeight = sliderImageHeight;
|
||||
this.randomX = randomX;
|
||||
}
|
||||
|
||||
public static ImageCaptchaInfo of(String backgroundImage,
|
||||
String sliderImage,
|
||||
Integer bgImageWidth,
|
||||
Integer bgImageHeight,
|
||||
Integer sliderImageWidth,
|
||||
Integer sliderImageHeight,
|
||||
Integer randomKey) {
|
||||
return new ImageCaptchaInfo( backgroundImage, sliderImage, bgImageWidth, bgImageHeight, sliderImageWidth, sliderImageHeight, randomKey);
|
||||
}
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2022/4/22 15:49
|
||||
* @Description 旋转图片
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class RotateImageCaptchaInfo extends ImageCaptchaInfo {
|
||||
/**
|
||||
* 旋转多少度
|
||||
*/
|
||||
private Double degree;
|
||||
|
||||
|
||||
|
||||
public static RotateImageCaptchaInfo of(Double degree,
|
||||
Integer randomX,
|
||||
String backgroundImage,
|
||||
String sliderImage,
|
||||
Integer bgImageWidth,
|
||||
Integer bgImageHeight,
|
||||
Integer sliderImageWidth,
|
||||
Integer sliderImageHeight) {
|
||||
RotateImageCaptchaInfo rotateImageCaptchaInfo = new RotateImageCaptchaInfo();
|
||||
rotateImageCaptchaInfo.setDegree(degree);
|
||||
rotateImageCaptchaInfo.setRandomX(randomX);
|
||||
rotateImageCaptchaInfo.setBackgroundImage(backgroundImage);
|
||||
rotateImageCaptchaInfo.setSliderImage(sliderImage);
|
||||
rotateImageCaptchaInfo.setBgImageWidth(bgImageWidth);
|
||||
rotateImageCaptchaInfo.setBgImageHeight(bgImageHeight);
|
||||
rotateImageCaptchaInfo.setSliderImageWidth(sliderImageWidth);
|
||||
rotateImageCaptchaInfo.setSliderImageHeight(sliderImageHeight);
|
||||
return rotateImageCaptchaInfo;
|
||||
}
|
||||
|
||||
}
|
||||
-66
@@ -1,66 +0,0 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @Date 2020/5/29 8:04
|
||||
* @Description 滑块验证码
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class SliderCaptchaInfo {
|
||||
|
||||
/**
|
||||
* x轴
|
||||
*/
|
||||
private Integer x;
|
||||
/**
|
||||
* y轴
|
||||
*/
|
||||
private Integer y;
|
||||
/**
|
||||
* 背景图
|
||||
*/
|
||||
private String backgroundImage;
|
||||
/**
|
||||
* 移动图
|
||||
*/
|
||||
private String sliderImage;
|
||||
/** 背景图片宽度. */
|
||||
private Integer bgImageWidth;
|
||||
/** 背景图片高度. */
|
||||
private Integer bgImageHeight;
|
||||
/** 滑块图片宽度. */
|
||||
private Integer sliderImageWidth;
|
||||
/** 滑块图片高度. */
|
||||
private Integer sliderImageHeight;
|
||||
/**
|
||||
* 扩展字段
|
||||
*/
|
||||
public Object expand;
|
||||
|
||||
public SliderCaptchaInfo(Integer x, Integer y, String backgroundImage, String sliderImage, Integer bgImageWidth, Integer bgImageHeight, Integer sliderImageWidth, Integer sliderImageHeight) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.backgroundImage = backgroundImage;
|
||||
this.sliderImage = sliderImage;
|
||||
this.bgImageWidth = bgImageWidth;
|
||||
this.bgImageHeight = bgImageHeight;
|
||||
this.sliderImageWidth = sliderImageWidth;
|
||||
this.sliderImageHeight = sliderImageHeight;
|
||||
}
|
||||
|
||||
public static SliderCaptchaInfo of(Integer x,
|
||||
Integer y,
|
||||
String backgroundImage,
|
||||
String sliderImage,
|
||||
Integer bgImageWidth,
|
||||
Integer bgImageHeight,
|
||||
Integer sliderImageWidth,
|
||||
Integer sliderImageHeight) {
|
||||
return new SliderCaptchaInfo(x, y, backgroundImage, sliderImage, bgImageWidth, bgImageHeight, sliderImageWidth, sliderImageHeight);
|
||||
}
|
||||
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.common.model.dto;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class SliderImageCaptchaInfo extends ImageCaptchaInfo {
|
||||
/**
|
||||
* x轴
|
||||
*/
|
||||
private Integer x;
|
||||
/**
|
||||
* y轴
|
||||
*/
|
||||
private Integer y;
|
||||
|
||||
|
||||
public static SliderImageCaptchaInfo of(Integer x,
|
||||
Integer y,
|
||||
String backgroundImage,
|
||||
String sliderImage,
|
||||
Integer bgImageWidth,
|
||||
Integer bgImageHeight,
|
||||
Integer sliderImageWidth,
|
||||
Integer sliderImageHeight) {
|
||||
SliderImageCaptchaInfo sliderImageCaptchaInfo = new SliderImageCaptchaInfo();
|
||||
sliderImageCaptchaInfo.setX(x);
|
||||
sliderImageCaptchaInfo.setY(y);
|
||||
sliderImageCaptchaInfo.setRandomX(x);
|
||||
sliderImageCaptchaInfo.setBackgroundImage(backgroundImage);
|
||||
sliderImageCaptchaInfo.setSliderImage(sliderImage);
|
||||
sliderImageCaptchaInfo.setBgImageWidth(bgImageWidth);
|
||||
sliderImageCaptchaInfo.setBgImageHeight(bgImageHeight);
|
||||
sliderImageCaptchaInfo.setSliderImageWidth(sliderImageWidth);
|
||||
sliderImageCaptchaInfo.setSliderImageHeight(sliderImageHeight);
|
||||
|
||||
return sliderImageCaptchaInfo;
|
||||
}
|
||||
|
||||
}
|
||||
+17
-22
@@ -1,8 +1,8 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||
|
||||
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.SliderCaptchaGenerator;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.SliderCaptchaInfo;
|
||||
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.SliderCaptchaResourceManager;
|
||||
import lombok.Getter;
|
||||
@@ -22,12 +22,12 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||
* @Description 滑块验证码缓冲器
|
||||
*/
|
||||
@Slf4j
|
||||
public class CacheSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
||||
public class CacheImageCaptchaGenerator implements ImageCaptchaGenerator {
|
||||
|
||||
protected final ScheduledExecutorService scheduledExecutor = new ScheduledThreadPoolExecutor(1, new NamedThreadFactory("slider-captcha-queue"));
|
||||
protected ConcurrentLinkedQueue<SliderCaptchaInfo> queue;
|
||||
protected ConcurrentLinkedQueue<ImageCaptchaInfo> queue;
|
||||
protected AtomicInteger pos = new AtomicInteger(0);
|
||||
protected SliderCaptchaGenerator target;
|
||||
protected ImageCaptchaGenerator target;
|
||||
protected int size;
|
||||
/** 等待时间,一般报错或者拉取为空时会休眠一段时间再试. */
|
||||
protected int waitTime = 1000;
|
||||
@@ -39,13 +39,13 @@ public class CacheSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
||||
@Setter
|
||||
protected boolean requiredGetCaptcha = true;
|
||||
|
||||
public CacheSliderCaptchaGenerator(SliderCaptchaGenerator target, GenerateParam generateParam, int size) {
|
||||
public CacheImageCaptchaGenerator(ImageCaptchaGenerator target, GenerateParam generateParam, int size) {
|
||||
this.target = target;
|
||||
this.generateParam = generateParam;
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public CacheSliderCaptchaGenerator(SliderCaptchaGenerator target, GenerateParam generateParam, int size, int waitTime, int period) {
|
||||
public CacheImageCaptchaGenerator(ImageCaptchaGenerator target, GenerateParam generateParam, int size, int waitTime, int period) {
|
||||
this.target = target;
|
||||
this.generateParam = generateParam;
|
||||
this.size = size;
|
||||
@@ -71,7 +71,7 @@ public class CacheSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
||||
if (pos.get() >= size) {
|
||||
return;
|
||||
}
|
||||
SliderCaptchaInfo slideImageInfo = target.generateSlideImageInfo(generateParam);
|
||||
ImageCaptchaInfo slideImageInfo = target.generateCaptchaImage(generateParam);
|
||||
if (slideImageInfo != null) {
|
||||
boolean addStatus = queue.offer(slideImageInfo);
|
||||
if (addStatus) {
|
||||
@@ -101,17 +101,17 @@ public class CacheSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public SliderCaptchaInfo generateSlideImageInfo() {
|
||||
return generateSlideImageInfo(this.requiredGetCaptcha);
|
||||
public ImageCaptchaInfo generateCaptchaImage(String type) {
|
||||
return generateCaptchaImage(this.requiredGetCaptcha);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
public SliderCaptchaInfo generateSlideImageInfo(boolean requiredGetCaptcha) {
|
||||
SliderCaptchaInfo poll = queue.poll();
|
||||
public ImageCaptchaInfo generateCaptchaImage(boolean requiredGetCaptcha) {
|
||||
ImageCaptchaInfo poll = queue.poll();
|
||||
if (poll == null && requiredGetCaptcha) {
|
||||
log.warn("滑块验证码缓存不足, genParam:{}", generateParam);
|
||||
// 如果池内没数据, 则直接生成
|
||||
return target.generateSlideImageInfo(generateParam);
|
||||
return target.generateCaptchaImage(generateParam);
|
||||
}
|
||||
// 减1
|
||||
pos.decrementAndGet();
|
||||
@@ -119,18 +119,13 @@ public class CacheSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public SliderCaptchaInfo generateSlideImageInfo(String targetFormatName, String matrixFormatName) {
|
||||
return target.generateSlideImageInfo(targetFormatName, matrixFormatName);
|
||||
public ImageCaptchaInfo generateCaptchaImage(String type, String targetFormatName, String matrixFormatName) {
|
||||
return target.generateCaptchaImage(type,targetFormatName, matrixFormatName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SliderCaptchaInfo generateSlideImageInfo(GenerateParam param) {
|
||||
return target.generateSlideImageInfo(param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean percentageContrast(Float newPercentage, Float oriPercentage) {
|
||||
return target.percentageContrast(newPercentage, oriPercentage);
|
||||
public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) {
|
||||
return target.generateCaptchaImage(param);
|
||||
}
|
||||
|
||||
@Override
|
||||
+26
-99
@@ -1,24 +1,25 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.GenerateParam;
|
||||
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.constant.SliderCaptchaConstant;
|
||||
import cloud.tianai.captcha.template.slider.generator.SliderCaptchaGenerator;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.SliderCaptchaInfo;
|
||||
import cloud.tianai.captcha.template.slider.resource.impl.provider.ClassPathResourceProvider;
|
||||
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
||||
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.SliderImageCaptchaInfo;
|
||||
import cloud.tianai.captcha.template.slider.resource.ResourceStore;
|
||||
import cloud.tianai.captcha.template.slider.resource.SliderCaptchaResourceManager;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.*;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
import static cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils.*;
|
||||
@@ -29,7 +30,7 @@ import static cloud.tianai.captcha.template.slider.common.util.CaptchaImageUtils
|
||||
* @Description 滑块验证码模板
|
||||
*/
|
||||
@Slf4j
|
||||
public class StandardSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
||||
public class StandardImageCaptchaGenerator extends AbstractImageCaptchaGenerator {
|
||||
|
||||
/**
|
||||
* 默认的resource资源文件路径.
|
||||
@@ -40,59 +41,28 @@ public class StandardSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
||||
*/
|
||||
public static final String DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH = "META-INF/cut-image/template";
|
||||
|
||||
public static String DEFAULT_BG_IMAGE_TYPE = "jpeg";
|
||||
public static String DEFAULT_SLIDER_IMAGE_TYPE = "png";
|
||||
public static float DEFAULT_TOLERANT = 0.02f;
|
||||
|
||||
protected final SliderCaptchaResourceManager sliderCaptchaResourceManager;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
/** 容错值. */
|
||||
public float tolerant = DEFAULT_TOLERANT;
|
||||
@Getter
|
||||
@Setter
|
||||
/** 默认背景图片类型. */
|
||||
public String defaultBgImageType = DEFAULT_BG_IMAGE_TYPE;
|
||||
@Getter
|
||||
@Setter
|
||||
/** 默认滑块图片类型. */
|
||||
public String defaultSliderImageType = DEFAULT_SLIDER_IMAGE_TYPE;
|
||||
|
||||
public StandardSliderCaptchaGenerator(SliderCaptchaResourceManager sliderCaptchaResourceManager,
|
||||
boolean initDefaultResource) {
|
||||
public StandardImageCaptchaGenerator(SliderCaptchaResourceManager sliderCaptchaResourceManager,
|
||||
boolean initDefaultResource) {
|
||||
this.sliderCaptchaResourceManager = sliderCaptchaResourceManager;
|
||||
if (initDefaultResource) {
|
||||
initDefaultResource();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SliderCaptchaInfo generateSlideImageInfo() {
|
||||
return generateSlideImageInfo(defaultBgImageType, defaultSliderImageType);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public SliderCaptchaInfo generateSlideImageInfo(String backgroundFormatName, String sliderFormatName) {
|
||||
return generateSlideImageInfo(GenerateParam.builder()
|
||||
.backgroundFormatName(backgroundFormatName)
|
||||
.sliderFormatName(sliderFormatName)
|
||||
.obfuscate(false)
|
||||
.build());
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public SliderCaptchaInfo generateSlideImageInfo(GenerateParam param) {
|
||||
public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) {
|
||||
Boolean obfuscate = param.getObfuscate();
|
||||
Map<String, Resource> templateImages = sliderCaptchaResourceManager.randomGetTemplate();
|
||||
Map<String, Resource> templateImages = sliderCaptchaResourceManager.randomGetTemplate(param.getType());
|
||||
if (templateImages == null || templateImages.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Collection<InputStream> inputStreams = new LinkedList<>();
|
||||
try {
|
||||
Resource resourceImage = sliderCaptchaResourceManager.randomGetResource();
|
||||
Resource resourceImage = sliderCaptchaResourceManager.randomGetResource(param.getType());
|
||||
InputStream resourceInputStream = sliderCaptchaResourceManager.getResourceInputStream(resourceImage);
|
||||
inputStreams.add(resourceInputStream);
|
||||
BufferedImage cutBackground = wrapFile2BufferedImage(resourceInputStream);
|
||||
@@ -151,16 +121,16 @@ public class StandardSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
||||
* @return SliderCaptchaInfo
|
||||
*/
|
||||
@SneakyThrows
|
||||
public SliderCaptchaInfo wrapSliderCaptchaInfo(int randomX,
|
||||
int randomY,
|
||||
BufferedImage backgroundImage,
|
||||
BufferedImage sliderImage,
|
||||
GenerateParam param) {
|
||||
public SliderImageCaptchaInfo wrapSliderCaptchaInfo(int randomX,
|
||||
int randomY,
|
||||
BufferedImage backgroundImage,
|
||||
BufferedImage sliderImage,
|
||||
GenerateParam param) {
|
||||
String backgroundFormatName = param.getBackgroundFormatName();
|
||||
String sliderFormatName = param.getSliderFormatName();
|
||||
String backGroundImageBase64 = transform(backgroundImage, backgroundFormatName);
|
||||
String sliderImageBase64 = transform(sliderImage, sliderFormatName);
|
||||
return SliderCaptchaInfo.of(randomX, randomY,
|
||||
return SliderImageCaptchaInfo.of(randomX, randomY,
|
||||
backGroundImageBase64,
|
||||
sliderImageBase64,
|
||||
backgroundImage.getWidth(), backgroundImage.getHeight(),
|
||||
@@ -168,41 +138,6 @@ public class StandardSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 将图片转换成字符串格式
|
||||
*
|
||||
* @param bufferedImage 图片
|
||||
* @param formatType 格式化类型
|
||||
* @return String
|
||||
*/
|
||||
public String transform(BufferedImage bufferedImage, String formatType) throws IOException {
|
||||
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
|
||||
ImageIO.write(bufferedImage, formatType, byteArrayOutputStream);
|
||||
//转换成字节码
|
||||
byte[] data = byteArrayOutputStream.toByteArray();
|
||||
String base64 = Base64.getEncoder().encodeToString(data);
|
||||
return "data:image/" + formatType + ";base64,".concat(base64);
|
||||
}
|
||||
|
||||
/**
|
||||
* 百分比对比
|
||||
*
|
||||
* @param newPercentage 用户百分比
|
||||
* @param oriPercentage 原百分比
|
||||
* @return true 成功 false 失败
|
||||
*/
|
||||
@Override
|
||||
public boolean percentageContrast(Float newPercentage, Float oriPercentage) {
|
||||
if (newPercentage == null || Float.isNaN(newPercentage) || Float.isInfinite(newPercentage)
|
||||
|| oriPercentage == null || Float.isNaN(oriPercentage) || Float.isInfinite(oriPercentage)) {
|
||||
return false;
|
||||
}
|
||||
// 容错值
|
||||
float maxTolerant = oriPercentage + tolerant;
|
||||
float minTolerant = oriPercentage - tolerant;
|
||||
return newPercentage >= minTolerant && newPercentage <= maxTolerant;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SliderCaptchaResourceManager getSlideImageResourceManager() {
|
||||
return sliderCaptchaResourceManager;
|
||||
@@ -217,34 +152,26 @@ public class StandardSliderCaptchaGenerator implements SliderCaptchaGenerator {
|
||||
return ThreadLocalRandom.current().nextInt(slWidth, sliderX - slWidth);
|
||||
}
|
||||
|
||||
protected InputStream getTemplateFile(Map<String, Resource> templateImages, String imageName) {
|
||||
Resource resource = templateImages.get(imageName);
|
||||
if (resource == null) {
|
||||
throw new IllegalArgumentException("查找模板异常, 该模板下未找到 ".concat(imageName));
|
||||
}
|
||||
return sliderCaptchaResourceManager.getResourceInputStream(resource);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化默认资源
|
||||
*/
|
||||
public void initDefaultResource() {
|
||||
ResourceStore resourceStore = sliderCaptchaResourceManager.getResourceStore();
|
||||
// 添加一些系统的资源文件
|
||||
resourceStore.addResource(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")));
|
||||
|
||||
// 添加一些系统的 模板文件
|
||||
Map<String, Resource> template1 = new HashMap<>(4);
|
||||
template1.put(SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/1/active.png")));
|
||||
template1.put(SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/1/fixed.png")));
|
||||
template1.put(SliderCaptchaConstant.TEMPLATE_MATRIX_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/1/matrix.png")));
|
||||
resourceStore.addTemplate(template1);
|
||||
resourceStore.addTemplate(CaptchaTypeConstant.SLIDER, template1);
|
||||
|
||||
|
||||
Map<String, Resource> template2 = new HashMap<>(4);
|
||||
template2.put(SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/2/active.png")));
|
||||
template2.put(SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/2/fixed.png")));
|
||||
template2.put(SliderCaptchaConstant.TEMPLATE_MATRIX_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/2/matrix.png")));
|
||||
resourceStore.addTemplate(template2);
|
||||
resourceStore.addTemplate(CaptchaTypeConstant.SLIDER, template2);
|
||||
}
|
||||
}
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
package cloud.tianai.captcha.template.slider.generator.impl;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.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.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;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.RotateImageCaptchaInfo;
|
||||
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.impl.provider.ClassPathResourceProvider;
|
||||
import lombok.SneakyThrows;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
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.impl.StandardImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_RESOURCE_PATH;
|
||||
import static cloud.tianai.captcha.template.slider.generator.impl.StandardImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
* @date 2022/4/22 16:43
|
||||
* @Description 旋转图片验证码生成器
|
||||
*/
|
||||
public class StandardRotateCaptchaGenerator extends AbstractImageCaptchaGenerator {
|
||||
|
||||
protected final SliderCaptchaResourceManager sliderCaptchaResourceManager;
|
||||
|
||||
public StandardRotateCaptchaGenerator(SliderCaptchaResourceManager sliderCaptchaResourceManager, boolean initDefaultResource) {
|
||||
this.sliderCaptchaResourceManager = sliderCaptchaResourceManager;
|
||||
if (initDefaultResource) {
|
||||
initDefaultResource();
|
||||
}
|
||||
}
|
||||
|
||||
public void initDefaultResource() {
|
||||
ResourceStore resourceStore = sliderCaptchaResourceManager.getResourceStore();
|
||||
// 添加一些系统的资源文件
|
||||
resourceStore.addResource(CaptchaTypeConstant.ROTATE, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
|
||||
|
||||
// 添加一些系统的 模板文件
|
||||
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_FIXED_IMAGE_NAME, new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/3/fixed.png")));
|
||||
resourceStore.addTemplate(CaptchaTypeConstant.ROTATE, template1);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageCaptchaInfo generateCaptchaImage(GenerateParam param) {
|
||||
// 旋转验证码没有混淆
|
||||
Boolean obfuscate = param.getObfuscate();
|
||||
Map<String, Resource> templateImages = sliderCaptchaResourceManager.randomGetTemplate(param.getType());
|
||||
if (templateImages == null || templateImages.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
Collection<InputStream> inputStreams = new LinkedList<>();
|
||||
try {
|
||||
Resource resourceImage = sliderCaptchaResourceManager.randomGetResource(param.getType());
|
||||
InputStream resourceInputStream = sliderCaptchaResourceManager.getResourceInputStream(resourceImage);
|
||||
inputStreams.add(resourceInputStream);
|
||||
BufferedImage cutBackground = wrapFile2BufferedImage(resourceInputStream);
|
||||
// 拷贝一份图片
|
||||
BufferedImage targetBackground = deepCopyBufferedImage(cutBackground);
|
||||
|
||||
InputStream fixedTemplateInput = getTemplateFile(templateImages, SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME);
|
||||
inputStreams.add(fixedTemplateInput);
|
||||
BufferedImage fixedTemplate = wrapFile2BufferedImage(fixedTemplateInput);
|
||||
|
||||
InputStream activeTemplateInput = getTemplateFile(templateImages, SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME);
|
||||
inputStreams.add(activeTemplateInput);
|
||||
BufferedImage activeTemplate = wrapFile2BufferedImage(activeTemplateInput);
|
||||
// 算出居中的x和y
|
||||
int x = targetBackground.getWidth() / 2 - fixedTemplate.getWidth() / 2;
|
||||
int y = targetBackground.getHeight() / 2 - fixedTemplate.getHeight() / 2;
|
||||
overlayImage(targetBackground, fixedTemplate, x, y);
|
||||
// 抠图部分
|
||||
BufferedImage cutImage = cutImage(cutBackground, fixedTemplate, x, y);
|
||||
overlayImage(cutImage, activeTemplate, 0, 0);
|
||||
// 随机旋转抠图部分
|
||||
// 随机x, 转换为角度
|
||||
int randomX = ThreadLocalRandom.current().nextInt(fixedTemplate.getWidth() + 10, targetBackground.getWidth() - 10);
|
||||
double degree = randomX / ((targetBackground.getWidth()) / 360d);
|
||||
// int degree = ThreadLocalRandom.current().nextInt(10, 350);
|
||||
cutImage = rotateImage(cutImage, degree);
|
||||
return wrapRotateCaptchaInfo(degree, randomX, targetBackground, cutImage, param);
|
||||
} finally {
|
||||
// 使用完后关闭流
|
||||
for (InputStream inputStream : inputStreams) {
|
||||
try {
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
private ImageCaptchaInfo wrapRotateCaptchaInfo(double degree, int randomX, BufferedImage backgroundImage, BufferedImage sliderImage, GenerateParam param) {
|
||||
String backgroundFormatName = param.getBackgroundFormatName();
|
||||
String sliderFormatName = param.getSliderFormatName();
|
||||
String backGroundImageBase64 = transform(backgroundImage, backgroundFormatName);
|
||||
String sliderImageBase64 = transform(sliderImage, sliderFormatName);
|
||||
return RotateImageCaptchaInfo.of(degree,
|
||||
randomX,
|
||||
backGroundImageBase64,
|
||||
sliderImageBase64,
|
||||
backgroundImage.getWidth(), backgroundImage.getHeight(),
|
||||
sliderImage.getWidth(), sliderImage.getHeight()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SliderCaptchaResourceManager getSlideImageResourceManager() {
|
||||
return sliderCaptchaResourceManager;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
BufferedImage bgImage = CaptchaImageUtils.wrapFile2BufferedImage(
|
||||
new FileInputStream("E:\\projects\\tianai-captcha\\src\\main\\resources\\META-INF\\cut-image\\resource\\1.jpg"));
|
||||
BufferedImage image1 = CaptchaImageUtils.wrapFile2BufferedImage(new FileInputStream("C:\\Users\\Thinkpad\\Desktop\\a.png"));
|
||||
BufferedImage image2 = CaptchaImageUtils.wrapFile2BufferedImage(new FileInputStream("C:\\Users\\Thinkpad\\Desktop\\b.png"));
|
||||
|
||||
BufferedImage cutImage = CaptchaImageUtils.cutImage(bgImage, image1, bgImage.getWidth() / 2 - 100, bgImage.getHeight() / 2 - 100);
|
||||
CaptchaImageUtils.overlayImage(cutImage, image2, 0, 0);
|
||||
cutImage = CaptchaImageUtils.rotateImage(cutImage, 180);
|
||||
CaptchaImageUtils.overlayImage(bgImage, image1, bgImage.getWidth() / 2 - 100, bgImage.getHeight() / 2 - 100);
|
||||
FileOutputStream fileOutputStream = new FileOutputStream("C:\\Users\\Thinkpad\\Desktop\\a1.jpg");
|
||||
FileOutputStream file2OutputStream = new FileOutputStream("C:\\Users\\Thinkpad\\Desktop\\a2.png");
|
||||
ImageIO.write(bgImage, "jpeg", fileOutputStream);
|
||||
ImageIO.write(cutImage, "png", file2OutputStream);
|
||||
fileOutputStream.close();
|
||||
file2OutputStream.close();
|
||||
}
|
||||
}
|
||||
@@ -12,97 +12,97 @@ public interface ResourceStore {
|
||||
*
|
||||
* @param resource 资源
|
||||
*/
|
||||
void addResource(Resource resource);
|
||||
void addResource(String type, Resource resource);
|
||||
|
||||
/**
|
||||
* 设置资源
|
||||
* 清除某个类型下的所有资源
|
||||
*
|
||||
* @param resources resources
|
||||
* @param type type
|
||||
*/
|
||||
void setResource(List<Resource> resources);
|
||||
|
||||
/**
|
||||
* 删除资源
|
||||
*
|
||||
* @param resource resource
|
||||
*/
|
||||
boolean deleteResource(Resource resource);
|
||||
void clearResources(String type);
|
||||
|
||||
/**
|
||||
* 清除所有资源
|
||||
*/
|
||||
void clearResources();
|
||||
|
||||
/**
|
||||
* 添加模板
|
||||
*
|
||||
* @param template template
|
||||
*/
|
||||
void addTemplate(Map<String, Resource> template);
|
||||
|
||||
|
||||
/**
|
||||
* 设置模板
|
||||
*
|
||||
* @param templateResource templateResource
|
||||
*/
|
||||
void setTemplates(List<Map<String, Resource>> templateResource);
|
||||
|
||||
/**
|
||||
* 删除模板
|
||||
*
|
||||
* @param template template
|
||||
*/
|
||||
void deleteTemplate(Map<String, Resource> template);
|
||||
|
||||
/**
|
||||
* 清除所有模板
|
||||
*/
|
||||
void clearTemplates();
|
||||
|
||||
void clearAllResources();
|
||||
|
||||
/**
|
||||
* 获取所有资源对象
|
||||
*
|
||||
* @return List<Resource>
|
||||
*/
|
||||
List<Resource> listResources();
|
||||
Map<String,List<Resource>> listAllResources();
|
||||
|
||||
/**
|
||||
* 获取所有模板
|
||||
* 获取某个type下的所有资源对象
|
||||
*
|
||||
* @return List<Map < String, Resource>>
|
||||
* @param type type
|
||||
* @return List<Resource>
|
||||
*/
|
||||
List<Map<String, Resource>> listTemplates();
|
||||
List<Resource> listResourcesByType(String type);
|
||||
|
||||
/**
|
||||
* 随机获取某个资源
|
||||
*
|
||||
* @param type type
|
||||
* @return Resource
|
||||
*/
|
||||
Resource randomGetResource(String type);
|
||||
|
||||
/**
|
||||
* 获取资源总数
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
int getResourceCount();
|
||||
int getAllResourceCount();
|
||||
|
||||
/**
|
||||
* 获取模板count
|
||||
* 获取某个type下的资源总数
|
||||
*
|
||||
* @param type type
|
||||
* @return int
|
||||
*/
|
||||
int getTemplateCount();
|
||||
int getResourceCount(String type);
|
||||
|
||||
/**
|
||||
* 获取资源通过index
|
||||
* 添加模板
|
||||
*
|
||||
* @param index index
|
||||
* @return Resource
|
||||
* @param template template
|
||||
*/
|
||||
Resource getResourceByIndex(int index);
|
||||
void addTemplate(String type, Map<String, Resource> template);
|
||||
|
||||
/**
|
||||
* 获取模板通过indx
|
||||
* 清除所有模板
|
||||
*/
|
||||
void clearAllTemplates();
|
||||
|
||||
/**
|
||||
* 清除某个type下的所有模板
|
||||
*
|
||||
* @param index index
|
||||
* @param type type
|
||||
*/
|
||||
void clearTemplates(String type);
|
||||
|
||||
/**
|
||||
* 获取所有模板通过type
|
||||
*
|
||||
* @return List<Map < String, Resource>>
|
||||
*/
|
||||
List<Map<String, Resource>> listTemplatesByType(String type);
|
||||
|
||||
/**
|
||||
* 获取所有模板
|
||||
*
|
||||
* @return Map<String, List < Map < String, Resource>>>
|
||||
*/
|
||||
Map<String, List<Map<String, Resource>>> listAllTemplates();
|
||||
|
||||
/**
|
||||
* 随机获取某个模板通过type
|
||||
*
|
||||
* @param type type
|
||||
* @return Map<String, Resource>
|
||||
*/
|
||||
Map<String, Resource> getTemplateByIndex(int index);
|
||||
Map<String, Resource> randomGetTemplateByType(String type);
|
||||
|
||||
}
|
||||
|
||||
+2
-2
@@ -18,14 +18,14 @@ public interface SliderCaptchaResourceManager {
|
||||
*
|
||||
* @return Map<String, Resource>
|
||||
*/
|
||||
Map<String, Resource> randomGetTemplate();
|
||||
Map<String, Resource> randomGetTemplate(String type);
|
||||
|
||||
/**
|
||||
* 随机获取某个资源对象
|
||||
*
|
||||
* @return Resource
|
||||
*/
|
||||
Resource randomGetResource();
|
||||
Resource randomGetResource(String type);
|
||||
|
||||
/**
|
||||
* 获取真正的资源流通过资源对象
|
||||
|
||||
+75
-59
@@ -1,12 +1,11 @@
|
||||
package cloud.tianai.captcha.template.slider.resource.impl;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.common.util.CollectionUtils;
|
||||
import cloud.tianai.captcha.template.slider.resource.ResourceStore;
|
||||
import cloud.tianai.captcha.template.slider.resource.common.model.dto.Resource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
@@ -17,86 +16,103 @@ public class DefaultResourceStore implements ResourceStore {
|
||||
/**
|
||||
* 模板资源.
|
||||
*/
|
||||
private List<Map<String, Resource>> templateResourceList = new ArrayList<>(2);
|
||||
private Map<String, List<Map<String, Resource>>> templateResourceMap = new HashMap<>(2);
|
||||
|
||||
/**
|
||||
* resource.
|
||||
*/
|
||||
private List<Resource> resourceList = new ArrayList<>(20);
|
||||
private Map<String, List<Resource>> resourceMap = new HashMap<>(2);
|
||||
|
||||
@Override
|
||||
public void addResource(Resource resource) {
|
||||
resourceList.add(resource);
|
||||
public void addResource(String type, Resource resource) {
|
||||
resourceMap.computeIfAbsent(type, k -> new ArrayList<>(20)).add(resource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResource(List<Resource> resources) {
|
||||
resourceList = new ArrayList<>(resources);
|
||||
public void clearResources(String type) {
|
||||
resourceMap.remove(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean deleteResource(Resource resource) {
|
||||
return resourceList.remove(resource);
|
||||
public void clearAllResources() {
|
||||
resourceMap.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearResources() {
|
||||
resourceList.clear();
|
||||
public Map<String, List<Resource>> listAllResources() {
|
||||
return resourceMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTemplate(Map<String, Resource> template) {
|
||||
templateResourceList.add(template);
|
||||
public List<Resource> listResourcesByType(String type) {
|
||||
return resourceMap.getOrDefault(type, Collections.emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTemplates(List<Map<String, Resource>> templateResource) {
|
||||
templateResourceList = new ArrayList<>(templateResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteTemplate(Map<String, Resource> template) {
|
||||
templateResourceList.remove(template);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTemplates() {
|
||||
templateResourceList.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Resource> listResources() {
|
||||
return Collections.unmodifiableList(resourceList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Resource>> listTemplates() {
|
||||
return Collections.unmodifiableList(templateResourceList);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResourceCount() {
|
||||
return resourceList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTemplateCount() {
|
||||
return templateResourceList.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource getResourceByIndex(int index) {
|
||||
if (index < 0 || index > resourceList.size() - 1) {
|
||||
throw new IllegalArgumentException("错误的index");
|
||||
public Resource randomGetResource(String type) {
|
||||
List<Resource> resources = resourceMap.get(type);
|
||||
if (CollectionUtils.isEmpty(resources)) {
|
||||
throw new IllegalStateException("随机获取资源错误,store中资源为空, type:" + type);
|
||||
}
|
||||
return resourceList.get(index);
|
||||
if (resources.size() == 1) {
|
||||
return resources.get(0);
|
||||
}
|
||||
int randomIndex = ThreadLocalRandom.current().nextInt(resources.size());
|
||||
return resources.get(randomIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Resource> getTemplateByIndex(int index) {
|
||||
if (index < 0 || index > templateResourceList.size() - 1) {
|
||||
throw new IllegalArgumentException("错误的index");
|
||||
public int getAllResourceCount() {
|
||||
int count = 0;
|
||||
for (List<Resource> value : resourceMap.values()) {
|
||||
count += value.size();
|
||||
}
|
||||
return templateResourceList.get(index);
|
||||
return count;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getResourceCount(String type) {
|
||||
return resourceMap.getOrDefault(type, Collections.emptyList()).size();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addTemplate(String type, Map<String, Resource> template) {
|
||||
templateResourceMap.computeIfAbsent(type, k -> new ArrayList<>(2)).add(template);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearAllTemplates() {
|
||||
templateResourceMap.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTemplates(String type) {
|
||||
templateResourceMap.remove(type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Map<String, Resource>> listTemplatesByType(String type) {
|
||||
return templateResourceMap.getOrDefault(type, Collections.emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, List<Map<String, Resource>>> listAllTemplates() {
|
||||
return templateResourceMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Resource> randomGetTemplateByType(String type) {
|
||||
List<Map<String, Resource>> templateList = templateResourceMap.get(type);
|
||||
if (CollectionUtils.isEmpty(templateList)) {
|
||||
throw new IllegalStateException("随机获取模板错误,store中模板为空, type:" + type);
|
||||
}
|
||||
|
||||
if (templateList.size() == 1) {
|
||||
return templateList.get(0);
|
||||
}
|
||||
int randomIndex = ThreadLocalRandom.current().nextInt(templateList.size());
|
||||
return templateList.get(randomIndex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-19
@@ -13,7 +13,6 @@ import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* @Author: 天爱有情
|
||||
@@ -47,29 +46,21 @@ public class DefaultSliderCaptchaResourceManager implements SliderCaptchaResourc
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Resource> randomGetTemplate() {
|
||||
int count = resourceStore.getTemplateCount();
|
||||
if (count < 1) {
|
||||
throw new IllegalStateException("随机获取模板错误,store中模板为空");
|
||||
public Map<String, Resource> randomGetTemplate(String type) {
|
||||
Map<String, Resource> resourceMap = resourceStore.randomGetTemplateByType(type);
|
||||
if (resourceMap == null) {
|
||||
throw new IllegalStateException("随机获取模板错误,store中模板为空, type:" + type);
|
||||
}
|
||||
if (count == 1) {
|
||||
return resourceStore.getTemplateByIndex(0);
|
||||
}
|
||||
int randomIndex = ThreadLocalRandom.current().nextInt(count);
|
||||
return resourceStore.getTemplateByIndex(randomIndex);
|
||||
return resourceMap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource randomGetResource() {
|
||||
int count = resourceStore.getResourceCount();
|
||||
if (count < 1) {
|
||||
throw new IllegalStateException("随机获取资源错误,store中资源为空");
|
||||
public Resource randomGetResource(String type) {
|
||||
Resource resource = resourceStore.randomGetResource(type);
|
||||
if (resource == null) {
|
||||
throw new IllegalStateException("随机获取资源错误,store中资源为空, type:" + type);
|
||||
}
|
||||
if (count == 1) {
|
||||
return resourceStore.getResourceByIndex(0);
|
||||
}
|
||||
int randomIndex = ThreadLocalRandom.current().nextInt(count);
|
||||
return resourceStore.getResourceByIndex(randomIndex);
|
||||
return resource;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
package cloud.tianai.captcha.template.slider.validator;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.SliderCaptchaInfo;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||
import cloud.tianai.captcha.template.slider.validator.common.model.dto.SliderCaptchaTrack;
|
||||
|
||||
import java.util.Map;
|
||||
@@ -43,10 +43,10 @@ public interface SliderCaptchaValidator {
|
||||
/**
|
||||
* 用于生成验证码校验时需要的回传参数
|
||||
*
|
||||
* @param sliderCaptchaInfo 生成的验证码数据
|
||||
* @param imageCaptchaInfo 生成的验证码数据
|
||||
* @return Map<String, Object>
|
||||
*/
|
||||
Map<String, Object> generateSliderCaptchaValidData(SliderCaptchaInfo sliderCaptchaInfo);
|
||||
Map<String, Object> generateSliderCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo);
|
||||
|
||||
/**
|
||||
* 校验用户滑动滑块是否正确
|
||||
|
||||
+5
-5
@@ -1,7 +1,7 @@
|
||||
package cloud.tianai.captcha.template.slider.validator.impl;
|
||||
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.SliderCaptchaInfo;
|
||||
import cloud.tianai.captcha.template.slider.common.util.CollectionUtils;
|
||||
import cloud.tianai.captcha.template.slider.generator.common.model.dto.ImageCaptchaInfo;
|
||||
import cloud.tianai.captcha.template.slider.validator.SliderCaptchaValidator;
|
||||
import cloud.tianai.captcha.template.slider.validator.common.model.dto.SliderCaptchaTrack;
|
||||
import lombok.Getter;
|
||||
@@ -56,9 +56,9 @@ public class SimpleSliderCaptchaValidator implements SliderCaptchaValidator {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> generateSliderCaptchaValidData(SliderCaptchaInfo sliderCaptchaInfo) {
|
||||
public Map<String, Object> generateSliderCaptchaValidData(ImageCaptchaInfo imageCaptchaInfo) {
|
||||
Map<String, Object> map = new HashMap<>(8);
|
||||
addPercentage(sliderCaptchaInfo, map);
|
||||
addPercentage(imageCaptchaInfo, map);
|
||||
return map;
|
||||
}
|
||||
|
||||
@@ -106,8 +106,8 @@ public class SimpleSliderCaptchaValidator implements SliderCaptchaValidator {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void addPercentage(SliderCaptchaInfo sliderCaptchaInfo, Map<String, Object> sliderCaptchaValidData) {
|
||||
float percentage = calcPercentage(sliderCaptchaInfo.getX(), sliderCaptchaInfo.getBgImageWidth());
|
||||
protected void addPercentage(ImageCaptchaInfo imageCaptchaInfo, Map<String, Object> sliderCaptchaValidData) {
|
||||
float percentage = calcPercentage(imageCaptchaInfo.getRandomX(), imageCaptchaInfo.getBgImageWidth());
|
||||
sliderCaptchaValidData.put("percentage", percentage);
|
||||
}
|
||||
}
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.1 KiB |
@@ -0,0 +1,37 @@
|
||||
package example;
|
||||
|
||||
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.RotateImageCaptchaInfo;
|
||||
import cloud.tianai.captcha.template.slider.generator.impl.StandardRotateCaptchaGenerator;
|
||||
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.impl.DefaultResourceStore;
|
||||
import cloud.tianai.captcha.template.slider.resource.impl.DefaultSliderCaptchaResourceManager;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class StandardRotateCaptchaGeneratorTest {
|
||||
|
||||
public static void main(String[] args) {
|
||||
ResourceStore resourceStore = new DefaultResourceStore();
|
||||
// Map<String, Resource> template = new HashMap<>();
|
||||
// template.put(SliderCaptchaConstant.TEMPLATE_FIXED_IMAGE_NAME, new Resource("file", "C:\\Users\\Thinkpad\\Desktop\\a.png"));
|
||||
// template.put(SliderCaptchaConstant.TEMPLATE_ACTIVE_IMAGE_NAME, new Resource("file", "C:\\Users\\Thinkpad\\Desktop\\b.png"));
|
||||
|
||||
// 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"));
|
||||
|
||||
SliderCaptchaResourceManager sliderCaptchaResourceManager = new DefaultSliderCaptchaResourceManager(resourceStore);
|
||||
|
||||
StandardRotateCaptchaGenerator standardRotateCaptchaGenerator = new StandardRotateCaptchaGenerator(sliderCaptchaResourceManager, true);
|
||||
ImageCaptchaInfo imageCaptchaInfo = standardRotateCaptchaGenerator.generateCaptchaImage(CaptchaTypeConstant.ROTATE);
|
||||
System.out.println("backgroundImage:" + imageCaptchaInfo.getBackgroundImage());
|
||||
System.out.println("sliderImage:" + imageCaptchaInfo.getSliderImage());
|
||||
System.out.println(((RotateImageCaptchaInfo)imageCaptchaInfo).getDegree());
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user