1
0
mirror of https://github.com/whvcse/EasyCaptcha.git synced 2024-11-23 10:09:19 +08:00

优化验证码效果

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> <groupId>com.github.whvcse</groupId>
<artifactId>EasyCaptcha</artifactId> <artifactId>EasyCaptcha</artifactId>
<version>1.4.0-RELEASE</version> <version>1.5.0-RELEASE</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>EasyCaptcha</name> <name>EasyCaptcha</name>

View File

@ -1,7 +1,6 @@
package com.wf.captcha; package com.wf.captcha;
import java.awt.Color; import java.awt.*;
import java.awt.Font;
import java.io.OutputStream; import java.io.OutputStream;
/** /**
@ -9,8 +8,8 @@ import java.io.OutputStream;
* Created by 王帆 on 2018-07-27 上午 10:08. * Created by 王帆 on 2018-07-27 上午 10:08.
*/ */
public abstract class Captcha extends Randoms { public abstract class Captcha extends Randoms {
protected Font font = new Font("Arial", Font.PLAIN, 32); // 字体Verdana protected Font font = new Font("Arial", Font.BOLD, 32); // 字体Verdana
protected int len = 5; // 验证码随机字符长度 protected int len = 4; // 验证码随机字符长度
protected int width = 130; // 验证码显示宽度 protected int width = 130; // 验证码显示宽度
protected int height = 48; // 验证码显示高度 protected int height = 48; // 验证码显示高度
protected String chars = null; // 当前验证码 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_DEFAULT = 1; // 字母数字混合
public static final int TYPE_ONLY_NUMBER = 2; // 纯数字 public static final int TYPE_ONLY_NUMBER = 2; // 纯数字
public static final int TYPE_ONLY_CHAR = 3; // 纯字母 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}}; 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: case 3:
cs[i] = alpha(charMinIndex, charMaxIndex); cs[i] = alpha(charMinIndex, charMaxIndex);
break; 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: default:
cs[i] = alpha(); 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() { public Font getFont() {
return font; return font;
} }

View File

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

View File

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

View File

@ -32,7 +32,7 @@ public class GifCaptcha extends Captcha {
@Override @Override
public boolean out(OutputStream os) { public boolean out(OutputStream os) {
checkAlpha(); checkAlpha();
boolean ok = false; boolean ok;
try { try {
char[] rands = textChar(); // 获取验证码数组 char[] rands = textChar(); // 获取验证码数组
GifEncoder gifEncoder = new GifEncoder(); GifEncoder gifEncoder = new GifEncoder();
@ -77,35 +77,27 @@ public class GifCaptcha extends Captcha {
g2d.setColor(Color.WHITE); g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height); g2d.fillRect(0, 0, width, height);
// 抗锯齿 // 抗锯齿
g2d.setFont(font);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 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++) { drawLine(2, g2d);
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));
}
// 画验证码 // 画验证码
int hp = (height - font.getSize()) >> 1; int hp = (height - font.getSize()) >> 1;
int h = height - hp; int h = height - hp;
int w = width / strs.length; 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++) { for (int i = 0; i < strs.length; i++) {
AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i)); AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));
g2d.setComposite(ac3); g2d.setComposite(ac3);
g2d.setColor(fontcolor[i]); g2d.setColor(fontcolor[i]);
// 计算坐标 // 计算坐标
int x = i * w + num(6); int x = i * w + sp + num(3);
int y = h - num(2, 8); int y = h - num(3, 6);
if (x < 0) { // 调整溢出的字
x = 0; if (x < 8) {
x = 8;
} }
if (x + font.getSize() > width) { if (x + font.getSize() > width) {
x = width - font.getSize(); x = width - font.getSize();
@ -116,6 +108,7 @@ public class GifCaptcha extends Captcha {
if (y - font.getSize() < 0) { if (y - font.getSize() < 0) {
y = font.getSize(); y = font.getSize();
} }
g2d.setFont(font.deriveFont(num(2) == 0 ? Font.PLAIN : Font.ITALIC));
g2d.drawString(String.valueOf(strs[i]), x, y); g2d.drawString(String.valueOf(strs[i]), x, y);
} }
g2d.dispose(); g2d.dispose();

View File

@ -15,6 +15,10 @@ public class Randoms {
protected static final int numMaxIndex = 8; // 数字的最大索引不包括最大值 protected static final int numMaxIndex = 8; // 数字的最大索引不包括最大值
protected static final int charMinIndex = numMaxIndex; // 字符的最小索引包括最小值 protected static final int charMinIndex = numMaxIndex; // 字符的最小索引包括最小值
protected static final int charMaxIndex = ALPHA.length; // 字符的最大索引不包括最大值 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 class SpecCaptcha extends Captcha {
public SpecCaptcha() { public SpecCaptcha() {
setFont(new Font(font.getFontName(), Font.ITALIC, font.getSize()));
} }
public SpecCaptcha(int width, int height) { public SpecCaptcha(int width, int height) {
@ -60,35 +59,26 @@ public class SpecCaptcha extends Captcha {
g.setColor(Color.WHITE); g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height); g.fillRect(0, 0, width, height);
// 抗锯齿 // 抗锯齿
g.setFont(font);
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 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++) { drawLine(3, g);
g.setColor(color(150, 250)); // 随机画干扰圆
g.setStroke(new BasicStroke(1.1f + RANDOM.nextFloat() / 2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); drawOval(8, g);
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));
}
// 画字符串 // 画字符串
AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.75f);// 指定透明度 AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f);// 指定透明度
g.setComposite(ac3); g.setComposite(ac3);
int hp = (height - font.getSize()) >> 1; int hp = (height - font.getSize()) >> 1;
int h = height - hp; int h = height - hp;
int w = width / strs.length; 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++) { for (int i = 0; i < strs.length; i++) {
g.setColor(new Color(20 + num(110), 20 + num(110), 20 + num(110))); g.setColor(new Color(20 + num(110), 20 + num(110), 20 + num(110)));
// 计算坐标 // 计算坐标
int x = i * w + num(10); int x = i * w + sp + num(3);
int y = h - num(9); int y = h - num(3, 6);
if (x < 0) { if (x < 8) {
x = 0; x = 8;
} }
if (x + font.getSize() > width) { if (x + font.getSize() > width) {
x = width - font.getSize(); x = width - font.getSize();
@ -99,6 +89,7 @@ public class SpecCaptcha extends Captcha {
if (y - font.getSize() < 0) { if (y - font.getSize() < 0) {
y = font.getSize(); y = font.getSize();
} }
g.setFont(font.deriveFont(num(2) == 0 ? Font.PLAIN : Font.ITALIC));
g.drawString(String.valueOf(strs[i]), x, y); g.drawString(String.valueOf(strs[i]), x, y);
} }
ImageIO.write(bi, "png", out); ImageIO.write(bi, "png", out);

View File

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