优化验证码效果

This commit is contained in:
whvcse@foxmail.com 2018-08-09 15:50:40 +08:00
parent 7defc7e727
commit 27af06eff5
9 changed files with 139 additions and 85 deletions

View File

@ -5,7 +5,7 @@
<groupId>com.github.whvcse</groupId>
<artifactId>EasyCaptcha</artifactId>
<version>1.4.0-RELEASE</version>
<version>1.5.0-RELEASE</version>
<packaging>jar</packaging>
<name>EasyCaptcha</name>

View File

@ -1,7 +1,6 @@
package com.wf.captcha;
import java.awt.Color;
import java.awt.Font;
import java.awt.*;
import java.io.OutputStream;
/**
@ -9,8 +8,8 @@ import java.io.OutputStream;
* Created by 王帆 on 2018-07-27 上午 10:08.
*/
public abstract class Captcha extends Randoms {
protected Font font = new Font("Arial", Font.PLAIN, 32); // 字体Verdana
protected int len = 5; // 验证码随机字符长度
protected Font font = new Font("Arial", Font.BOLD, 32); // 字体Verdana
protected int len = 4; // 验证码随机字符长度
protected int width = 130; // 验证码显示宽度
protected int height = 48; // 验证码显示高度
protected String chars = null; // 当前验证码
@ -18,6 +17,9 @@ public abstract class Captcha extends Randoms {
public static final int TYPE_DEFAULT = 1; // 字母数字混合
public static final int TYPE_ONLY_NUMBER = 2; // 纯数字
public static final int TYPE_ONLY_CHAR = 3; // 纯字母
public static final int TYPE_ONLY_UPPER = 4; // 纯大写字母
public static final int TYPE_ONLY_LOWER = 5; // 纯小写字母
public static final int TYPE_NUM_AND_UPPER = 6; // 数字大写字母
// 常用颜色
public static final int[][] COLOR = {{0, 135, 255}, {51, 153, 51}, {255, 102, 102}, {255, 153, 0}, {153, 102, 0}, {153, 102, 153}, {51, 153, 153}, {102, 102, 255}, {0, 102, 204}, {204, 51, 51}, {0, 153, 204}, {0, 51, 102}};
@ -36,6 +38,15 @@ public abstract class Captcha extends Randoms {
case 3:
cs[i] = alpha(charMinIndex, charMaxIndex);
break;
case 4:
cs[i] = alpha(upperMinIndex, upperMaxIndex);
break;
case 5:
cs[i] = alpha(lowerMinIndex, lowerMaxIndex);
break;
case 6:
cs[i] = alpha(upperMaxIndex);
break;
default:
cs[i] = alpha();
}
@ -109,6 +120,61 @@ public abstract class Captcha extends Randoms {
}
}
/**
* 随机画干扰线
*
* @param num 数量
* @param g Graphics2D
*/
public void drawLine(int num, Graphics2D g) {
drawLine(num, null, g);
}
/**
* 随机画干扰线
*
* @param num 数量
* @param color 颜色
* @param g Graphics2D
*/
public void drawLine(int num, Color color, Graphics2D g) {
for (int i = 0; i < num; i++) {
g.setColor(color == null ? color(150, 250) : color);
int x1 = num(-10, width - 10);
int y1 = num(5, height - 5);
int x2 = num(10, width + 10);
int y2 = num(2, height - 2);
g.drawLine(x1, y1, x2, y2);
}
}
/**
* 随机画干扰圆
*
* @param num 数量
* @param g Graphics2D
*/
public void drawOval(int num, Graphics2D g) {
for (int i = 0; i < num; i++) {
g.setColor(color(100, 250));
g.drawOval(num(width), num(height), 10 + num(20), 10 + num(20));
}
}
/**
* 随机画干扰圆
*
* @param num 数量
* @param color 颜色
* @param g Graphics2D
*/
public void drawOval(int num, Color color, Graphics2D g) {
for (int i = 0; i < num; i++) {
g.setColor(color == null ? color(100, 250) : color);
g.drawOval(num(width), num(height), 10 + num(20), 10 + num(20));
}
}
public Font getFont() {
return font;
}

View File

@ -58,7 +58,6 @@ public class ChineseCaptcha extends ChineseCaptchaAbstract {
g.fillRect(0, 0, width, height);
// 抗锯齿
g.setColor(color());
g.setFont(font);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int hp = (height - font.getSize()) >> 1;
int h = height - hp;
@ -69,8 +68,8 @@ public class ChineseCaptcha extends ChineseCaptchaAbstract {
// 计算坐标
int x = i * w + sp + num(-5, 5);
int y = h + num(-5, 5);
if (x < 0) {
x = 0;
if (x < 5) {
x = 5;
}
if (x + font.getSize() > width) {
x = width - font.getSize();
@ -81,21 +80,16 @@ public class ChineseCaptcha extends ChineseCaptchaAbstract {
if (y - font.getSize() < 0) {
y = font.getSize();
}
g.setFont(font.deriveFont(num(2) == 0 ? Font.PLAIN : Font.ITALIC));
g.drawString(String.valueOf(strs[i]), x, y);
}
// 随机画干扰线
g.setStroke(new BasicStroke(1.25f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
for (int i = 0; i < 6; i++) {
ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.75f); // 指定透明度
g.setComposite(ac3);
int x1 = num(-10, width - 10);
int y1 = num(5, height - 5);
int x2 = num(10, width + 10);
int y2 = num(2, height - 2);
g.drawLine(x1, y1, x2, y2);
// 画干扰圆圈
g.drawOval(num(width), num(height), 5 + num(25), 5 + num(25));
}
ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f); // 指定透明度
g.setComposite(ac3);
drawLine(2, g.getColor(), g);
// 画干扰圆圈
drawOval(5, g.getColor(), g);
ImageIO.write(bi, "png", out);
out.flush();
ok = true;

View File

@ -35,4 +35,16 @@ public abstract class ChineseCaptchaAbstract extends Captcha {
return DELTA.charAt(num(DELTA.length()));
}
@Override
public void drawLine(int num, Color color, Graphics2D g) {
for (int i = 0; i < num; i++) {
g.setColor(color == null ? color(150, 250) : color);
int x1 = num(-10, width / 3);
int y1 = num(5, height - 5);
int x2 = num(width / 3 * 2, width + 10);
int y2 = num(2, height - 2);
g.drawLine(x1, y1, x2, y2);
}
}
}

View File

@ -28,7 +28,7 @@ public class ChineseGifCaptcha extends ChineseCaptchaAbstract {
@Override
public boolean out(OutputStream os) {
checkAlpha();
boolean ok = false;
boolean ok;
try {
char[] rands = textChar(); // 获取验证码数组
GifEncoder gifEncoder = new GifEncoder();
@ -71,7 +71,6 @@ public class ChineseGifCaptcha extends ChineseCaptchaAbstract {
// 抗锯齿
AlphaComposite ac3;
g2d.setColor(fontcolor);
g2d.setFont(font);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 画验证码
int hp = (height - font.getSize()) >> 1;
@ -96,23 +95,16 @@ public class ChineseGifCaptcha extends ChineseCaptchaAbstract {
if (y - font.getSize() < 0) {
y = font.getSize();
}
g2d.setFont(font.deriveFont(num(2) == 0 ? Font.PLAIN : Font.ITALIC));
g2d.drawString(String.valueOf(strs[i]), x, y);
}
// 随机画干扰线
g2d.setStroke(new BasicStroke(1.25f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.45f);
g2d.setComposite(ac3);
for (int i = 0; i < 4; i++) {
int x1 = num(-10, width - 10);
int y1 = num(5, height - 5);
int x2 = num(10, width + 10);
int y2 = num(2, height - 2);
g2d.drawLine(x1, y1, x2, y2);
}
drawLine(1, g2d.getColor(), g2d);
// 画干扰圆圈
for (int i = 0; i < 8; i++) {
g2d.drawOval(num(width), num(height), 5 + num(50), 5 + num(50));
}
drawOval(3, g2d.getColor(), g2d);
g2d.dispose();
return image;
}

View File

@ -32,7 +32,7 @@ public class GifCaptcha extends Captcha {
@Override
public boolean out(OutputStream os) {
checkAlpha();
boolean ok = false;
boolean ok;
try {
char[] rands = textChar(); // 获取验证码数组
GifEncoder gifEncoder = new GifEncoder();
@ -77,35 +77,27 @@ public class GifCaptcha extends Captcha {
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height);
// 抗锯齿
g2d.setFont(font);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
// 画干扰圆圈
drawOval(4, g2d);
// 随机画干扰线
for (int i = 0; i < num(5, 12); i++) {
g2d.setStroke(new BasicStroke(1.1f + RANDOM.nextFloat() / 2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
g2d.setColor(color(150, 250));
int x1 = num(-10, width - 10);
int y1 = num(5, height - 5);
int x2 = num(10, width + 10);
int y2 = num(2, height - 2);
g2d.drawLine(x1, y1, x2, y2);
// 画干扰圆圈
g2d.setColor(color(100, 250));
g2d.drawOval(num(width), num(height), 5 + num(25), 5 + num(25));
}
drawLine(2, g2d);
// 画验证码
int hp = (height - font.getSize()) >> 1;
int h = height - hp;
int w = width / strs.length;
//int sp = (w - font.getSize()) / 2;
int sp = (w - font.getSize()) / 2;
for (int i = 0; i < strs.length; i++) {
AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));
g2d.setComposite(ac3);
g2d.setColor(fontcolor[i]);
// 计算坐标
int x = i * w + num(6);
int y = h - num(2, 8);
if (x < 0) {
x = 0;
int x = i * w + sp + num(3);
int y = h - num(3, 6);
// 调整溢出的字
if (x < 8) {
x = 8;
}
if (x + font.getSize() > width) {
x = width - font.getSize();
@ -116,6 +108,7 @@ public class GifCaptcha extends Captcha {
if (y - font.getSize() < 0) {
y = font.getSize();
}
g2d.setFont(font.deriveFont(num(2) == 0 ? Font.PLAIN : Font.ITALIC));
g2d.drawString(String.valueOf(strs[i]), x, y);
}
g2d.dispose();

View File

@ -15,6 +15,10 @@ public class Randoms {
protected static final int numMaxIndex = 8; // 数字的最大索引不包括最大值
protected static final int charMinIndex = numMaxIndex; // 字符的最小索引包括最小值
protected static final int charMaxIndex = ALPHA.length; // 字符的最大索引不包括最大值
protected static final int upperMinIndex = charMinIndex; // 大写字符最小索引
protected static final int upperMaxIndex = upperMinIndex + 23; // 大写字符最大索引
protected static final int lowerMinIndex = upperMaxIndex; // 小写字母最小索引
protected static final int lowerMaxIndex = charMaxIndex; // 小写字母最大索引
/**
* 产生两个数之间的随机数

View File

@ -14,7 +14,6 @@ import javax.imageio.ImageIO;
public class SpecCaptcha extends Captcha {
public SpecCaptcha() {
setFont(new Font(font.getFontName(), Font.ITALIC, font.getSize()));
}
public SpecCaptcha(int width, int height) {
@ -60,35 +59,26 @@ public class SpecCaptcha extends Captcha {
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
// 抗锯齿
g.setFont(font);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setStroke(new BasicStroke(1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
// 随机画干扰线
for (int i = 0; i < 12; i++) {
g.setColor(color(150, 250));
g.setStroke(new BasicStroke(1.1f + RANDOM.nextFloat() / 2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
int x1 = num(-10, width - 10);
int y1 = num(5, height - 5);
int x2 = num(10, width + 10);
int y2 = num(2, height - 2);
g.drawLine(x1, y1, x2, y2);
// 画干扰圆圈
g.setColor(color(100, 250));
g.drawOval(num(width), num(height), 5 + num(25), 5 + num(25));
}
drawLine(3, g);
// 随机画干扰圆
drawOval(8, g);
// 画字符串
AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.75f);// 指定透明度
AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f);// 指定透明度
g.setComposite(ac3);
int hp = (height - font.getSize()) >> 1;
int h = height - hp;
int w = width / strs.length;
//int sp = (w - font.getSize()) / 2;
int sp = (w - font.getSize()) / 2;
for (int i = 0; i < strs.length; i++) {
g.setColor(new Color(20 + num(110), 20 + num(110), 20 + num(110)));
// 计算坐标
int x = i * w + num(10);
int y = h - num(9);
if (x < 0) {
x = 0;
int x = i * w + sp + num(3);
int y = h - num(3, 6);
if (x < 8) {
x = 8;
}
if (x + font.getSize() > width) {
x = width - font.getSize();
@ -99,6 +89,7 @@ public class SpecCaptcha extends Captcha {
if (y - font.getSize() < 0) {
y = font.getSize();
}
g.setFont(font.deriveFont(num(2) == 0 ? Font.PLAIN : Font.ITALIC));
g.drawString(String.valueOf(strs[i]), x, y);
}
ImageIO.write(bi, "png", out);

View File

@ -13,37 +13,39 @@ public class CaptchaTest {
@Test
public void test() throws Exception {
for (int i = 0; i < 5; i++) {
/*for (int i = 0; i < 5; i++) {
SpecCaptcha specCaptcha = new SpecCaptcha();
//specCaptcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
specCaptcha.setCharType(Captcha.TYPE_ONLY_UPPER);
System.out.println(specCaptcha.text());
//specCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".png")));
}
specCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".png")));
}*/
}
@Test
public void testGIf() throws Exception {
for (int i = 0; i < 5; i++) {
/*for (int i = 0; i < 5; i++) {
GifCaptcha gifCaptcha = new GifCaptcha();
System.out.println(gifCaptcha.text());
//gifCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".gif")));
}
gifCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".gif")));
}*/
}
@Test
public void testHan() throws Exception {
// ChineseCaptcha chineseCaptcha = new ChineseCaptcha();
//chineseCaptcha.setFont(new Font("微软雅黑", Font.PLAIN, 25));
// System.out.println(chineseCaptcha.text());
//chineseCaptcha.out(new FileOutputStream(new File("D:/Java/aa.png")));
/*for (int i = 0; i < 5; i++) {
ChineseCaptcha chineseCaptcha = new ChineseCaptcha();
System.out.println(chineseCaptcha.text());
chineseCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".png")));
}*/
}
@Test
public void testGifHan() throws Exception {
// ChineseGifCaptcha chineseGifCaptcha = new ChineseGifCaptcha();
//chineseGifCaptcha.setFont(new Font("微软雅黑", Font.PLAIN, 30));
// System.out.println(chineseGifCaptcha.text());
//chineseGifCaptcha.out(new FileOutputStream(new File("D:/Java/aa.gif")));
/*for (int i = 0; i < 5; i++) {
ChineseGifCaptcha chineseGifCaptcha = new ChineseGifCaptcha();
System.out.println(chineseGifCaptcha.text());
chineseGifCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".gif")));
}*/
}
}