Java 生成验证码 Captcha

方法效率较低,推荐使用缓存,重复使用验证码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
// 验证码宽度
private static final Integer CAPTCHA_WIDTH = 150;
// 验证码高度
private static final Integer CAPTCHA_HEIGHT = 40;
// 验证码最大旋转角度(不推荐修改)
private static final Integer CAPTCHA_CHAR_ROTATE = 5;
// 干扰线数量
private static final Integer CAPTCHA_LINE_NUM = 5;
// 验证码数量
private static final Integer CAPTCHA_CHAR_NUM = 4;
// 验证码的保存格式
private static final String CAPTCHA_CONTENT_TYPE = "PNG";

public static String createCaptcha(OutputStream outputStream) throws PortableException {
BufferedImage image = new BufferedImage(CAPTCHA_WIDTH, CAPTCHA_HEIGHT, BufferedImage.TYPE_INT_BGR);
Graphics2D g = (Graphics2D) image.getGraphics();
g.fillRect(0, 0, CAPTCHA_WIDTH, CAPTCHA_HEIGHT);

for (int i = 0; i < CAPTCHA_LINE_NUM; i++) {
drawRandomLine(g);
}
for (int i = 0; i < CAPTCHA_LINE_NUM; i++) {
drawLeftToRightLine(g);
}
StringBuilder ans = new StringBuilder();
for (int i = 0; i < CAPTCHA_CHAR_NUM; i++) {
ans.append(drawString(g, i + 1));
}
try {
ImageIO.write(image, CAPTCHA_CONTENT_TYPE, outputStream);
} catch (IOException e) {
throw PortableException.of("B-01-002");
}
return ans.toString();
}

private static void drawRandomLine(Graphics2D g) {
int xs = RANDOM.nextInt(CAPTCHA_WIDTH);
int xe = RANDOM.nextInt(CAPTCHA_WIDTH);
int ys = RANDOM.nextInt(CAPTCHA_HEIGHT);
int ye = RANDOM.nextInt(CAPTCHA_HEIGHT);
g.setFont(ARIAL_FONT);
g.setColor(getRandomColor());
g.drawLine(xs, ys, xe, ye);
}

private static void drawLeftToRightLine(Graphics2D g) {
int xs = RANDOM.nextInt(CAPTCHA_WIDTH / 2);
int xe = CAPTCHA_WIDTH / 2 + RANDOM.nextInt(CAPTCHA_WIDTH / 2);
int ys = RANDOM.nextInt(CAPTCHA_HEIGHT / 2);
int ye = CAPTCHA_HEIGHT / 2 + RANDOM.nextInt(CAPTCHA_HEIGHT / 2);
g.setFont(ARIAL_FONT);
g.setColor(getRandomColor());
g.drawLine(xs, ys, xe, ye);
}

private static String drawString(Graphics2D g, Integer num) {
// 保证左侧和右侧不要贴边,总共留出一个字符的空间
int baseX = (int) (CAPTCHA_WIDTH * 1.0 / (ImageUtils.CAPTCHA_CHAR_NUM + 1) * num);
AffineTransform old = g.getTransform();
String c = getRandomChar();

g.setFont(ARIAL_FONT);
g.setColor(getRandomColor());
g.rotate(Math.toRadians(RANDOM.nextInt(CAPTCHA_CHAR_ROTATE * 2) - CAPTCHA_CHAR_ROTATE));
g.drawString(c, baseX, CAPTCHA_HEIGHT / 3 * 2);
g.setTransform(old);

return c;
}

private static Color getRandomColor() {
int upper = 128;
int lower = 0;
int r = lower + RANDOM.nextInt(upper);
int g = lower + RANDOM.nextInt(upper);
int b = lower + RANDOM.nextInt(upper);
return new Color(r, g, b);
}

private static String getRandomChar() {
return String.valueOf(CAPTCHA_CHAR.charAt(RANDOM.nextInt(CAPTCHA_CHAR.length())));
}

Java 生成验证码 Captcha
https://blog.mauve.icu/2022/03/19/develop-note/java-create-captcha/
作者
Shiroha
发布于
2022年3月19日
许可协议