+ 增加 CaptchaImageConverter转换器,负责将生成的图片转换成自己想要的格式,比如加密转码等..

This commit is contained in:
天爱有情
2022-02-16 10:43:19 +08:00
parent ab7ce28057
commit 2effcf4032
8 changed files with 488 additions and 387 deletions
@@ -0,0 +1,205 @@
package cloud.tianai.captcha.template.slider;
import cloud.tianai.captcha.template.slider.provider.ClassPathResourceProvider;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import java.awt.image.BufferedImage;
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.CaptchaImageUtils.*;
/**
* @Author: 天爱有情
* @Date 2020/5/29 8:06
* @Description 滑块验证码模板
*/
@Slf4j
public class StandardSliderCaptchaTemplate implements SliderCaptchaTemplate {
/**
* 默认的resource资源文件路径.
*/
public static final String DEFAULT_SLIDER_IMAGE_RESOURCE_PATH = "META-INF/cut-image/resource";
/**
* 默认的template资源文件路径.
*/
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;
protected final CaptchaImageConverter captchaImageConverter;
@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 StandardSliderCaptchaTemplate(SliderCaptchaResourceManager sliderCaptchaResourceManager,
CaptchaImageConverter captchaImageConverter,
boolean initDefaultResource) {
this.sliderCaptchaResourceManager = sliderCaptchaResourceManager;
this.captchaImageConverter = captchaImageConverter;
if (initDefaultResource) {
initDefaultResource();
}
}
@Override
public SliderCaptchaInfo getSlideImageInfo() {
return getSlideImageInfo(defaultBgImageType, defaultSliderImageType);
}
@SneakyThrows
@Override
public SliderCaptchaInfo getSlideImageInfo(String backgroundFormatName, String sliderFormatName) {
return getSlideImageInfo(GenerateParam.builder()
.backgroundFormatName(backgroundFormatName)
.sliderFormatName(sliderFormatName)
.obfuscate(false)
.build());
}
@SneakyThrows
@Override
public SliderCaptchaInfo getSlideImageInfo(GenerateParam param) {
Boolean obfuscate = param.getObfuscate();
Map<String, Resource> templateImages = sliderCaptchaResourceManager.randomGetTemplate();
if (templateImages == null || templateImages.isEmpty()) {
return null;
}
Collection<InputStream> inputStreams = new LinkedList<>();
try {
Resource resourceImage = sliderCaptchaResourceManager.randomGetResource();
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);
InputStream matrixTemplateInput = getTemplateFile(templateImages, SliderCaptchaConstant.TEMPLATE_MATRIX_IMAGE_NAME);
inputStreams.add(matrixTemplateInput);
BufferedImage matrixTemplate = wrapFile2BufferedImage(matrixTemplateInput);
// BufferedImage cutTemplate = warpFile2BufferedImage(getTemplateFile(templateImages, CUT_IMAGE_NAME));
// 获取随机的 x 和 y 轴
int randomX = ThreadLocalRandom.current().nextInt(targetBackground.getWidth() - fixedTemplate.getWidth() * 2) + fixedTemplate.getWidth();
int randomY = ThreadLocalRandom.current().nextInt(targetBackground.getHeight() - fixedTemplate.getHeight());
overlayImage(targetBackground, fixedTemplate, randomX, randomY);
if (obfuscate) {
// 加入混淆滑块
int obfuscateX = randomObfuscateX(randomX, fixedTemplate.getWidth(), targetBackground.getWidth());
overlayImage(targetBackground, fixedTemplate, obfuscateX, randomY);
}
BufferedImage cutImage = cutImage(cutBackground, fixedTemplate, randomX, randomY);
overlayImage(cutImage, activeTemplate, 0, 0);
overlayImage(matrixTemplate, cutImage, 0, randomY);
// 计算滑块百分比
float xPercent = (float) randomX / targetBackground.getWidth();
return captchaImageConverter.convert(OriginalSliderData.of(randomX, randomY, xPercent, targetBackground, matrixTemplate, param));
} finally {
// 使用完后关闭流
for (InputStream inputStream : inputStreams) {
try {
inputStream.close();
} catch (IOException e) {
// ignore
}
}
}
}
/**
* 百分比对比
*
* @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;
}
protected int randomObfuscateX(int sliderX, int slWidth, int bgWidth) {
if (bgWidth / 2 > (sliderX + (slWidth / 2))) {
// 右边混淆
return ThreadLocalRandom.current().nextInt(sliderX + slWidth, bgWidth - slWidth);
}
// 左边混淆
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")));
// 添加一些系统的 模板文件
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);
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);
}
}