Dependent SDK components
<dependency>
<groupId>io.github.mingyang66</groupId>
<artifactId>oceansky-captcha</artifactId>
<version>4.3.2</version>
</dependency>
1. There are three common graphic verification codes as follows:
- Mixed alphanumeric (noise lines);
- pure numbers (interference lines);
- plain letters (noise lines);
2. The sample diagram is as follows:
3. Case code
Question 1: Where is the point relative to the (x, y) coordinates of the drawn verification code?
Answer: upper left corner
Question 2: How to calculate the starting position of the x-coordinate for drawing the graphic verification code?
Answer: (artboard width - verification code character text width) /2
Question 3: How to calculate the x-coordinate position drawn by each character one by one?
Answer: starting x coordinate + (verification code width/number of verification code characters) * n-1th character
Question 4: How to calculate the y-axis coordinates to ensure that the verification code is centered up and down?
答案:(height - (fm.getAscent() + fm.getDescent())) / 2 + fm.getAscent();
Before understanding the above formula, you should first figure out what is baseline, ascent, descent, and lead
public class CaptchaUtils {
/**
* 数字
*/
private static final String[] DIGIT = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
/**
* 字母
*/
private static final String[] LETTER = {
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
/**
* 字母数字
*/
private static final String[] ALPHANUMERIC = {
"0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n",
"o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
"O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"};
/**
* 图片格式
*/
public static final String FORMAT_NAME = "JPEG";
/**
* @param width 画板宽度
* @param height 画板高度
* @param count 验证码个数
* @param fontSize 字体大小
* @return
* @Description: 绘制数字图形验证码,不带干扰线
*/
public static Captcha createDigit(int width, int height, int count, int fontSize) throws IOException {
return createDigit(width, height, count, fontSize, false, null);
}
/**
* @param width 画板宽度
* @param height 画板高度
* @param count 验证码个数
* @param fontSize 字体大小
* @param line 是否画干扰线
* @param lineCount 干扰线数量
* @return
* @Description: 绘制数字图形验证码
*/
public static Captcha createDigit(int width, int height, int count, int fontSize, boolean line, Integer lineCount) throws IOException {
/**
* 字体名又分为两大类:中文字体名:宋体,楷体,黑体等;
* 英文字体名:Arial,Times New Roman等;
*/
Font font = new Font("Times New Roman", Font.ITALIC, fontSize);
// 绘制的字符串
String[] code = getDrawCode(CaptchaType.DIGIT, count);
return create2D(width, height, code, font, line, lineCount);
}
/**
* @param width 画板宽度
* @param height 画板高度
* @param count 验证码个数
* @param fontSize 字体大小
* @return
* @throws IOException
* @Description: 绘制字母图形验证码
*/
public static Captcha createLetter(int width, int height, int count, int fontSize) throws IOException {
return createLetter(width, height, count, fontSize, false, null);
}
/**
* @param width 画板宽度
* @param height 画板高度
* @param count 验证码个数
* @param fontSize 字体大小
* @param line 是否画干扰线
* @param lineCount 干扰线数量
* @return
* @throws IOException
* @Description: 绘制字母图形验证码
*/
public static Captcha createLetter(int width, int height, int count, int fontSize, boolean line, Integer lineCount) throws IOException {
/**
* 字体名又分为两大类:中文字体名:宋体,楷体,黑体等;
* 英文字体名:Arial,Times New Roman等;
*/
Font font = new Font("Times New Roman", Font.ITALIC, fontSize);
// 绘制的字符串
String[] code = getDrawCode(CaptchaType.LETTER, count);
return create2D(width, height, code, font, line, lineCount);
}
/**
* @param width 画板宽度
* @param height 画板高度
* @param count 验证码个数
* @param fontSize 字体大小
* @return
* @throws IOException
* @Description: 绘制数字字母图形验证码
*/
public static Captcha createAlphanumeric(int width, int height, int count, int fontSize) throws IOException {
return createAlphanumeric(width, height, count, fontSize, false, null);
}
/**
* @param width 画板宽度
* @param height 画板高度
* @param count 验证码个数
* @param fontSize 字体大小
* @param line 是否画干扰线
* @param lineCount 干扰线数量
* @return
* @throws IOException
* @Description: 绘制数字字母图形验证码
*/
public static Captcha createAlphanumeric(int width, int height, int count, int fontSize, boolean line, Integer lineCount) throws IOException {
/**
* 字体名又分为两大类:中文字体名:宋体,楷体,黑体等;
* 英文字体名:Arial,Times New Roman等;
*/
Font font = new Font("Times New Roman", Font.ITALIC, fontSize);
// 绘制的字符串
String[] code = getDrawCode(CaptchaType.ALPHANUMERIC, count);
return create2D(width, height, code, font, line, lineCount);
}
/**
* @param width 画板宽度
* @param height 画板高度
* @param code 验证码
* @param font 字体
* @param line 是否绘制干扰线
* @param lineCount 干扰线条数
* @return 生成的图形验证码对象
* @throws IOException
* @Description: 生成图形验证码
*/
public static Captcha create2D(int width, int height, String[] code, Font font, boolean line, Integer lineCount) throws IOException {
// 创建空白图片
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
// 获取图片画笔
Graphics graphic = image.getGraphics();
// 绘制矩形背景(实心矩形)
graphic.fillRect(0, 0, width, height);
/**
* Font.PLAIN(普通)
* Font.BOLD(加粗)
* Font.ITALIC(斜体)
* Font.BOLD+ Font.ITALIC(粗斜体)
*/
graphic.setFont(font);
// 画图形验证码
drawCode(graphic, width, height, code);
// 画干扰线
if (line) {
drawLine(graphic, width, height, lineCount);
}
ByteArrayOutputStream bas = new ByteArrayOutputStream();
ImageIO.write(image, FORMAT_NAME, bas);
return new CaptchaBuilder().code(StringUtils.join(code)).image(bas.toByteArray()).build();
}
/**
* @param graphic 画板对象
* @param width 画板宽度
* @param height 画板高度
* @param code 图形验证码字符串
* @Description 画图形验证码
*/
protected static void drawCode(Graphics graphic, int width, int height, String[] code) {
// 计算文字长度,计算居中的x点坐标,即字符串左边位置
FontMetrics fm = graphic.getFontMetrics(graphic.getFont());
// 字符串宽度
int textWidth = fm.stringWidth(StringUtils.join(code));
// 字符串左侧x坐标
int x = (width - textWidth) / 2;
int y = (height - (fm.getAscent() + fm.getDescent())) / 2 + fm.getAscent();
for (int i = 0; i < code.length; i++) {
// 设置随机颜色
graphic.setColor(new Color(RandomUtils.nextInt(0, 255), RandomUtils.nextInt(0, 255), RandomUtils.nextInt(0, 255)));
// 绘制字符串
graphic.drawString(code[i], x + (textWidth / code.length) * i, y);
}
}
/**
* 获取绘制的验证码
*
* @param type 字符串类型
* @param count 字符个数
* @return 字符串数组
*/
protected static String[] getDrawCode(CaptchaType type, int count) {
String[] code = new String[count];
Random ran = new Random();
for (int i = 0; i < count; i++) {
switch (type) {
case DIGIT:
code[i] = DIGIT[ran.nextInt(DIGIT.length)];
break;
case LETTER:
code[i] = LETTER[ran.nextInt(LETTER.length)];
break;
default:
code[i] = ALPHANUMERIC[ran.nextInt(ALPHANUMERIC.length)];
break;
}
}
return code;
}
/**
* @param graphic 画板对象
* @param width 画板宽度
* @param height 画板高度
* @param lineCount 干扰线条数
* @Description 绘制干扰线
*/
protected static void drawLine(Graphics graphic, int width, int height, Integer lineCount) {
// 画干扰线
for (int i = 0; i < lineCount; i++) {
// 设置随机颜色
graphic.setColor(new Color(RandomUtils.nextInt(0, 255), RandomUtils.nextInt(0, 255), RandomUtils.nextInt(0, 255)));
// 随机画线
graphic.drawLine(RandomUtils.nextInt(0, width), RandomUtils.nextInt(0, height), RandomUtils.nextInt(0, width), RandomUtils.nextInt(0, height));
}
}
}
For the complete code of the case, please refer to: https://github.com/mingyang66/spring-parent