mirror of
https://github.com/dromara/tianai-captcha.git
synced 2026-05-07 14:13:05 +08:00
U 解决 java17默认不支持 FontDesignMetrics 类的问题, 故剔除该类 使用其它算法替代
This commit is contained in:
@@ -57,13 +57,15 @@ public abstract class AbstractImageCaptchaGenerator implements ImageCaptchaGener
|
||||
if (init) {
|
||||
return this;
|
||||
}
|
||||
init = true;
|
||||
try {
|
||||
log.info("图片验证码[{}]初始化...", this.getClass().getSimpleName());
|
||||
doInit();
|
||||
} catch (Exception e) {
|
||||
init = false;
|
||||
log.error("[{}]初始化失败,ex", this.getClass().getSimpleName(), e);
|
||||
throw e;
|
||||
}
|
||||
init = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@@ -322,7 +322,7 @@ public class CaptchaImageUtils {
|
||||
public static BufferedImage drawWordImg(Color fontColor,
|
||||
String word,
|
||||
Font font,
|
||||
FontDesignMetrics metrics,
|
||||
float fontTopCoef,
|
||||
int imgWidth,
|
||||
int imgHeight,
|
||||
float deg) {
|
||||
@@ -333,7 +333,7 @@ public class CaptchaImageUtils {
|
||||
g.setColor(fontColor);
|
||||
g.setFont(font);
|
||||
float left = (imgWidth - font.getSize()) / 2f;
|
||||
float top = (imgHeight - font.getSize()) / 2f + metrics.getAscent() - 6;
|
||||
float top = (imgHeight - font.getSize()) / 2f + font.getSize() - fontTopCoef;
|
||||
g.rotate(Math.toRadians(deg), imgWidth / 2f, imgHeight / 2f);
|
||||
g.drawString(word, left, top);
|
||||
g.dispose();
|
||||
@@ -405,7 +405,6 @@ public class CaptchaImageUtils {
|
||||
*
|
||||
* @param data 验证码内容
|
||||
* @param font 字体包
|
||||
* @param metrics FontDesignMetrics
|
||||
* @param width 验证码宽度
|
||||
* @param height 验证码高度
|
||||
* @param startX 起始X
|
||||
@@ -416,7 +415,6 @@ public class CaptchaImageUtils {
|
||||
*/
|
||||
public static BufferedImage genSimpleImgCaptcha(String data,
|
||||
Font font,
|
||||
FontDesignMetrics metrics,
|
||||
int width,
|
||||
int height,
|
||||
float startX,
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package cloud.tianai.captcha.generator.impl;
|
||||
|
||||
import cloud.tianai.captcha.common.util.NamedThreadFactory;
|
||||
import cloud.tianai.captcha.common.util.NamedThreadFactory;
|
||||
import cloud.tianai.captcha.generator.ImageCaptchaGenerator;
|
||||
import cloud.tianai.captcha.generator.common.model.dto.GenerateParam;
|
||||
@@ -69,49 +68,46 @@ public class CacheImageCaptchaGenerator implements ImageCaptchaGenerator {
|
||||
private void init(int z) {
|
||||
this.size = z;
|
||||
// 初始化一个队列扫描
|
||||
scheduledExecutor.scheduleAtFixedRate(() -> {
|
||||
queueMap.forEach((k, queue) -> {
|
||||
try {
|
||||
AtomicInteger pos = posMap.computeIfAbsent(k, k1 -> new AtomicInteger(0));
|
||||
int addCount = 0;
|
||||
while (pos.get() < this.size) {
|
||||
if (pos.get() >= size) {
|
||||
return;
|
||||
}
|
||||
ImageCaptchaInfo slideImageInfo = target.generateCaptchaImage(k);
|
||||
if (slideImageInfo != null) {
|
||||
boolean addStatus = queue.offer(slideImageInfo);
|
||||
addCount++;
|
||||
if (addStatus) {
|
||||
// 添加记录
|
||||
pos.incrementAndGet();
|
||||
}
|
||||
} else {
|
||||
sleep();
|
||||
}
|
||||
scheduledExecutor.scheduleAtFixedRate(() -> queueMap.forEach((k, queue) -> {
|
||||
try {
|
||||
AtomicInteger pos = posMap.computeIfAbsent(k, k1 -> new AtomicInteger(0));
|
||||
int addCount = 0;
|
||||
while (pos.get() < this.size) {
|
||||
if (pos.get() >= size) {
|
||||
return;
|
||||
}
|
||||
if (addCount == 0) {
|
||||
// 没有添加,检测最新更新时间 如果时间过长,直接清除数据
|
||||
Long lastUpdate = lastUpdateMap.get(k);
|
||||
if (lastUpdate != null && System.currentTimeMillis() - lastUpdate > expireTime) {
|
||||
queueMap.remove(k);
|
||||
posMap.remove(k);
|
||||
lastUpdateMap.remove(k);
|
||||
ImageCaptchaInfo slideImageInfo = target.generateCaptchaImage(k);
|
||||
if (slideImageInfo != null) {
|
||||
boolean addStatus = queue.offer(slideImageInfo);
|
||||
addCount++;
|
||||
if (addStatus) {
|
||||
// 添加记录
|
||||
pos.incrementAndGet();
|
||||
}
|
||||
} else {
|
||||
sleep();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// cache所有
|
||||
log.error("缓存队列扫描时出错, ex", e);
|
||||
// 删掉它
|
||||
queueMap.remove(k);
|
||||
posMap.remove(k);
|
||||
lastUpdateMap.remove(k);
|
||||
// 休眠
|
||||
sleep();
|
||||
}
|
||||
});
|
||||
|
||||
}, 0, period, TimeUnit.MILLISECONDS);
|
||||
if (addCount == 0) {
|
||||
// 没有添加,检测最新更新时间 如果时间过长,直接清除数据
|
||||
Long lastUpdate = lastUpdateMap.get(k);
|
||||
if (lastUpdate != null && System.currentTimeMillis() - lastUpdate > expireTime) {
|
||||
queueMap.remove(k);
|
||||
posMap.remove(k);
|
||||
lastUpdateMap.remove(k);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// cache所有
|
||||
log.error("缓存队列扫描时出错, ex", e);
|
||||
// 删掉它
|
||||
queueMap.remove(k);
|
||||
posMap.remove(k);
|
||||
lastUpdateMap.remove(k);
|
||||
// 休眠
|
||||
sleep();
|
||||
}
|
||||
}), 0, period, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private void sleep() {
|
||||
@@ -121,6 +117,11 @@ public class CacheImageCaptchaGenerator implements ImageCaptchaGenerator {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ImageCaptchaGenerator init() {
|
||||
return target.init();
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public ImageCaptchaInfo generateCaptchaImage(String type) {
|
||||
@@ -176,20 +177,4 @@ public class CacheImageCaptchaGenerator implements ImageCaptchaGenerator {
|
||||
public ImageCaptchaResourceManager getImageResourceManager() {
|
||||
return target.getImageResourceManager();
|
||||
}
|
||||
|
||||
|
||||
// public static void main(String[] args) throws InterruptedException {
|
||||
// SliderCaptchaTemplate captchaTemplate = new DefaultSliderCaptchaTemplate("jpeg", "png", true);
|
||||
//
|
||||
// captchaTemplate = new CacheSliderCaptchaTemplate(captchaTemplate, 20);
|
||||
// TimeUnit.SECONDS.sleep(5);
|
||||
// for (int i = 0; i < 100; i++) {
|
||||
// long start = System.currentTimeMillis();
|
||||
// SliderCaptchaInfo info = captchaTemplate.getSlideImageInfo();
|
||||
// long end = System.currentTimeMillis();
|
||||
// System.out.println("耗时:" + (end - start));
|
||||
// TimeUnit.MILLISECONDS.sleep(10);
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
+28
-11
@@ -13,10 +13,11 @@ import cloud.tianai.captcha.resource.impl.provider.ClassPathResourceProvider;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.SneakyThrows;
|
||||
import sun.font.FontDesignMetrics;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
@@ -36,9 +37,6 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
|
||||
protected Font font;
|
||||
@Getter
|
||||
@Setter
|
||||
protected FontDesignMetrics metrics;
|
||||
@Getter
|
||||
@Setter
|
||||
protected Integer clickImgWidth = 80;
|
||||
@Getter
|
||||
@Setter
|
||||
@@ -50,6 +48,16 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
|
||||
@Setter
|
||||
protected int tipImageInterferencePointNum = 5;
|
||||
|
||||
/**
|
||||
* 因为在画文字图形的时候 y 值不能准确通过 除法计算得出, 字体大小不一致中间的容错值不可估计,
|
||||
* 所以通过 线性回归模型 计算出 intercept和coef 用于计算 容错值
|
||||
* 训练数据为 宋体 字体大小为 30~150 随机选择7组数据进行训练, 训练后r2结果为 0.9967106324620846
|
||||
*/
|
||||
protected float intercept = 0.39583333f;
|
||||
protected float coef = 0.14645833f;
|
||||
|
||||
protected float currentFontTopCoef = 0.0f;
|
||||
|
||||
@SneakyThrows
|
||||
public StandardRandomWordClickImageCaptchaGenerator(ImageCaptchaResourceManager imageCaptchaResourceManager, boolean initDefaultResource) {
|
||||
super(imageCaptchaResourceManager, initDefaultResource);
|
||||
@@ -67,7 +75,8 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
|
||||
Font font = Font.createFont(Font.TRUETYPE_FONT, inputStream);
|
||||
this.font = font.deriveFont(Font.BOLD, 70);
|
||||
}
|
||||
this.metrics = FontDesignMetrics.getMetrics(font);
|
||||
// 计算容错
|
||||
currentFontTopCoef = coef * font.getSize() + intercept;
|
||||
if (initDefaultResource) {
|
||||
initDefaultResource();
|
||||
}
|
||||
@@ -88,20 +97,25 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
|
||||
resourceStore.addResource(CaptchaTypeConstant.WORD_IMAGE_CLICK, new Resource(ClassPathResourceProvider.NAME, StandardSliderImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_RESOURCE_PATH.concat("/1.jpg")));
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public ImgWrapper genTipImage(List<ClickImageCheckDefinition> imageCheckDefinitions) {
|
||||
String tips = imageCheckDefinitions.stream().map(ClickImageCheckDefinition::getTip).collect(Collectors.joining());
|
||||
// 生成随机颜色
|
||||
int fontWidth = metrics.stringWidth(tips);
|
||||
int width = fontWidth + 5;
|
||||
int height = metrics.getHeight() + 5;
|
||||
int fontWidth = tips.length() * font.getSize();
|
||||
int width = fontWidth + 6;
|
||||
int height = font.getSize() + 6;
|
||||
float left = (width - fontWidth) / 2f;
|
||||
float top = 5 / 2f + metrics.getAscent();
|
||||
float top = 6 / 2f + font.getSize() - currentFontTopCoef;
|
||||
BufferedImage bufferedImage = CaptchaImageUtils.genSimpleImgCaptcha(tips,
|
||||
font, metrics, width, height, left, top, tipImageInterferenceLineNum, tipImageInterferencePointNum);
|
||||
font, width, height, left, top, tipImageInterferenceLineNum, tipImageInterferencePointNum);
|
||||
FileOutputStream fileOutputStream = new FileOutputStream("d:/aaa/" + tips + ".png");
|
||||
ImageIO.write(bufferedImage, "png", fileOutputStream);
|
||||
fileOutputStream.close();
|
||||
return new ImgWrapper(bufferedImage, tips);
|
||||
}
|
||||
|
||||
@SneakyThrows
|
||||
@Override
|
||||
public ImgWrapper randomGetClickImg() {
|
||||
ThreadLocalRandom random = ThreadLocalRandom.current();
|
||||
@@ -114,10 +128,13 @@ public class StandardRandomWordClickImageCaptchaGenerator extends AbstractClickI
|
||||
BufferedImage fontImage = CaptchaImageUtils.drawWordImg(randomColor,
|
||||
randomWord,
|
||||
font,
|
||||
this.metrics,
|
||||
currentFontTopCoef,
|
||||
clickImgWidth,
|
||||
clickImgHeight,
|
||||
randomDeg);
|
||||
FileOutputStream fileOutputStream = new FileOutputStream("d:/aaa/" + randomWord + ".png");
|
||||
ImageIO.write(fontImage, "png", fileOutputStream);
|
||||
fileOutputStream.close();
|
||||
return new ImgWrapper(fontImage, randomWord);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user