diff --git a/README.md b/README.md
index d20491d..5f930bd 100644
--- a/README.md
+++ b/README.md
@@ -5,48 +5,54 @@
## 1.简介
+ Java图形验证码,支持gif、中文、算术等类型,可用于Java Web、JavaSE等项目。
- Java图形验证码,支持gif验证码、中文验证码,可用于Java Web、JavaSE项目。
-
+---
## 2.效果展示
-**gif效果:**
-
-![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd30vgc2g303m01c0st.jpg)
+![验证码](https://s2.ax1x.com/2019/08/23/msFrE8.png)
-![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd22ixh9g303m01c3yj.jpg)
+![验证码](https://s2.ax1x.com/2019/08/23/msF0DP.png)
-![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd2k0gjug303m01ct8t.jpg)
-
-**png效果:**
-
-![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd09lqpaj303m01cwee.jpg)
+![验证码](https://s2.ax1x.com/2019/08/23/msFwut.png)
+
+![验证码](https://s2.ax1x.com/2019/08/23/msFzVK.gif)
-![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd0tj6nhj303m01ct8m.jpg)
+![验证码](https://s2.ax1x.com/2019/08/23/msFvb6.gif)
-![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd1cw3pcj303m01c0sn.jpg)
+![验证码](https://s2.ax1x.com/2019/08/23/msFXK1.gif)
+**算术类型:**
-**中文验证码:**
-
-![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovnvbgx6g303m01cjrc.jpg)
+![验证码](https://s2.ax1x.com/2019/08/23/mskKPg.png)
-![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovojp2gng303m01cq2w.jpg)
+![验证码](https://s2.ax1x.com/2019/08/23/msknIS.png)
-![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovp5u4c4g303m01cdft.jpg)
+![验证码](https://s2.ax1x.com/2019/08/23/mskma8.png)
-![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovmfxg71j303m01cq2s.jpg)
+**中文类型:**
+
+![验证码](https://s2.ax1x.com/2019/08/23/mskcdK.png)
-![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovmy720dj303m01cq2s.jpg)
+![验证码](https://s2.ax1x.com/2019/08/23/msk6Z6.png)
-![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovn68um6j303m01cglf.jpg)
+![验证码](https://s2.ax1x.com/2019/08/23/msksqx.png)
+
+**内置字体:**
+
+![验证码](https://s2.ax1x.com/2019/08/23/msAVSJ.png)
+
+![验证码](https://s2.ax1x.com/2019/08/23/msAAW4.png)
+
+![验证码](https://s2.ax1x.com/2019/08/23/msAkYF.png)
+---
## 3.导入项目
-### 2.1.gradle方式的引入
+### 3.1.gradle方式的引入
需要先在project的build.gradle中添加:
```text
allprojects {
@@ -58,11 +64,11 @@ allprojects {
在项目的build.gradle中添加
```text
dependencies {
- compile 'com.github.whvcse:EasyCaptcha:1.5.0'
+ compile 'com.github.whvcse:EasyCaptcha:1.6.0'
}
```
-### 2.2.maven方式引入
+### 3.2.maven方式引入
在你的pom.xml中添加如下代码:
```xml
@@ -77,33 +83,49 @@ dependencies {
com.github.whvcse
EasyCaptcha
- 1.5.0
+ 1.6.0
-
```
-### 2.3.jar包下载
-[EasyCaptcha-1.5.0.jar](https://gitee.com/whvse/EasyCaptcha/releases)
+### 3.3.jar包下载
+[EasyCaptcha-1.6.0.jar](https://gitee.com/whvse/EasyCaptcha/releases)
maven导入jar包,在项目根目录创建`libs`文件夹,然后pom.xml添加如下:
```
com.github.whvcse
EasyCaptcha
- 1.5.0
- ${basedir}/libs/EasyCaptcha-1.5.0.jar
+ 1.6.0
+ ${basedir}/libs/EasyCaptcha-1.6.0.jar
```
---
+## 4.使用方法
-## 3.使用方法
+### 4.1.在SpringMVC中使用
+```java
+@Controller
+public class CaptchaController {
+
+ @RequestMapping("/captcha")
+ public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
+ CaptchaUtil.out(request, response);
+ }
+}
+```
+前端html代码:
+```html
+
+```
-### 3.1.快速使用
-1.在web.xml里面加入如下配置:
+> 不要忘了把`/captcha`路径排除登录拦截,比如shiro的拦截。
+
+### 4.2.在servlet中使用
+web.xml中配置servlet:
```xml
@@ -113,163 +135,130 @@ maven导入jar包,在项目根目录创建`libs`文件夹,然后pom.xml添
CaptchaServlet
- /images/captcha
+ /captcha
```
-2.前端代码
+前端html代码:
```html
-
+
```
-### 3.2.在SpringMVC中使用
-也可以使用controller的形式输出验证码,方法如下:
-```java
-@Controller
-public class MainController {
-
- @RequestMapping("/images/captcha")
- public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
- CaptchaUtil.out(request, response);
- }
-}
-```
-前端代码:
-```html
-
-```
-
-### 3.3.判断验证码是否正确
+### 4.3.判断验证码是否正确
```java
@Controller
public class LoginController {
@PostMapping("/login")
- public JsonResult login(String username,String password,String code){
-
- if (!CaptchaUtil.ver(code, request)) {
- CaptchaUtil.clear(request);
+ public JsonResult login(String username,String password,String verCode){
+ if (!CaptchaUtil.ver(verCode, request)) {
+ CaptchaUtil.clear(request); // 清除session中的验证码
return JsonResult.error("验证码不正确");
}
}
}
```
-### 3.4.设置宽高和位数
+### 4.4.设置宽高和位数
```java
@Controller
-public class MainController {
+public class CaptchaController {
- @RequestMapping("/images/captcha")
+ @RequestMapping("/captcha")
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 设置位数
CaptchaUtil.out(5, request, response);
-
// 设置宽、高、位数
CaptchaUtil.out(130, 48, 5, request, response);
+
+ // 使用gif验证码
+ GifCaptcha gifCaptcha = new GifCaptcha(130,48,4);
+ CaptchaUtil.out(gifCaptcha, request, response);
}
}
```
-### 3.5.不使用工具类
-
- CaptchaUtil是为了简化操作,封装了生成验证码、存session、判断验证码等功能。CaptchaUtil使用的GifCaptcha
-生成的字母数字混合的gif验证码,如果需要设置更多的参数,请参照如下操作使用:
+### 4.5.不使用工具类
+ CaptchaUtil封装了输出验证码、存session、判断验证码等功能,也可以不使用此工具类:
```java
@Controller
-public class MainController {
+public class CaptchaController {
- @RequestMapping("/images/captcha")
+ @RequestMapping("/captcha")
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 设置请求头为输出图片类型
- CaptchaUtil.setHeader(response);
+ response.setContentType("image/gif");
+ response.setHeader("Pragma", "No-cache");
+ response.setHeader("Cache-Control", "no-cache");
+ response.setDateHeader("Expires", 0);
// 三个参数分别为宽、高、位数
- GifCaptcha gifCaptcha = new GifCaptcha(130, 48, 5);
-
+ SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
// 设置字体
- gifCaptcha.setFont(new Font("Verdana", Font.PLAIN, 32)); // 有默认字体,可以不用设置
-
+ specCaptcha.setFont(new Font("Verdana", Font.PLAIN, 32)); // 有默认字体,可以不用设置
// 设置类型,纯数字、纯字母、字母数字混合
- gifCaptcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
+ specCaptcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
// 验证码存入session
- request.getSession().setAttribute("captcha", gifCaptcha.text().toLowerCase());
+ request.getSession().setAttribute("captcha", specCaptcha.text().toLowerCase());
// 输出图片流
- gifCaptcha.out(response.getOutputStream());
+ specCaptcha.out(response.getOutputStream());
}
@PostMapping("/login")
- public JsonResult login(String username,String password,String code){
+ public JsonResult login(String username,String password,String verCode){
// 获取session中的验证码
String sessionCode = request.getSession().getAttribute("captcha");
// 判断验证码
- if (code==null || !sessionCode.equals(code.trim().toLowerCase())) {
+ if (verCode==null || !sessionCode.equals(verCode.trim().toLowerCase())) {
return JsonResult.error("验证码不正确");
}
}
}
```
-## 4.更多设置
+## 5.更多设置
-### 4.1.使用Gif验证码
+### 5.1.验证码类型
```java
public class Test {
public static void main(String[] args) {
- OutputStream outputStream = new FileOutputStream(new File("D:/a/aa.gif"));
+ // png类型
+ SpecCaptcha captcha = new SpecCaptcha(130, 48, 5);
+ captcha.text(); // 获取验证码的字符
+ captcha.textChar(); // 获取验证码的字符数组
- // 三个参数分别为宽、高、位数
- GifCaptcha gifCaptcha = new GifCaptcha(130, 48, 5);
+ // gif类型
+ GifCaptcha captcha = new GifCaptcha(130, 48, 5);
- // 设置字体
- gifCaptcha.setFont(new Font("Verdana", Font.PLAIN, 32)); // 有默认字体,可以不用设置
+ // 中文类型
+ ChineseCaptcha captcha = new ChineseCaptcha(130, 48, 5);
- // 设置类型,纯数字、纯字母、字母数字混合
- gifCaptcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
+ // 中文gif类型
+ ChineseGifCaptcha captcha = new ChineseGifCaptcha(130, 48, 5);
- // 生成的验证码
- String code = gifCaptcha.text();
+ // 算术类型
+ ArithmeticCaptcha captcha = new ArithmeticCaptcha(130, 48, 5);
+ captcha.setLen(3); // 几位数运算,默认是两位
+ captcha.getArithmeticString(); // 获取运算的公式:3+2=?
+ captcha.text(); // 获取运算的结果:5
- // 输出图片流
- gifCaptcha.out(outputStream);
+ captcha.out(outputStream); // 输出验证码
}
}
```
-### 4.2.使用png验证码
+> 注意:
+> 算术验证码的len表示是几位数运算,而其他验证码的len表示验证码的位数,算术验证码的text()表示的是公式的结果,
+> 对于算术验证码,你应该把公式的结果存储session,而不是公式。
-```java
-public class Test {
-
- public static void main(String[] args) {
- OutputStream outputStream = new FileOutputStream(new File("D:/a/aa.png"));
-
- // 三个参数分别为宽、高、位数
- SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
-
- // 设置字体
- specCaptcha.setFont(new Font("Verdana", Font.PLAIN, 32)); // 有默认字体,可以不用设置
-
- // 设置类型,纯数字、纯字母、字母数字混合
- specCaptcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
-
- // 生成的验证码
- String code = specCaptcha.text();
-
- // 输出图片流
- specCaptcha.out(outputStream);
- }
-}
-```
-
-### 4.3.验证码类型
+### 5.2.验证码字符类型
类型 | 描述
:--- | :---
@@ -280,60 +269,145 @@ public class Test {
TYPE_ONLY_LOWER | 纯小写字母
TYPE_NUM_AND_UPPER | 数字和大写字母
-
-### 4.4.中文验证码
-
-中文png验证码:
-
-```java
-public class Test {
-
- public static void main(String[] args) {
- OutputStream outputStream = new FileOutputStream(new File("D:/a/aa.png"));
-
- // 三个参数分别为宽、高、位数
- ChineseCaptcha chineseCaptcha = new ChineseCaptcha(130, 48, 4);
-
- // 设置字体
- chineseCaptcha.setFont(new Font("楷体", Font.PLAIN, 28)); // 有默认字体,可以不用设置
-
- // 生成的验证码
- String code = chineseCaptcha.text();
-
- // 输出图片流
- chineseCaptcha.out(outputStream);
- }
-}
+使用方法:
+```
+SpecCaptcha captcha = new SpecCaptcha(130, 48, 5);
+captcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
```
-中文gif验证码:
+> 只有`SpecCaptcha`和`GifCaptcha`设置才有效果。
-```java
-public class Test {
-
- public static void main(String[] args) {
- OutputStream outputStream = new FileOutputStream(new File("D:/a/aa.png"));
-
- // 三个参数分别为宽、高、位数
- ChineseGifCaptcha chineseGifCaptcha = new ChineseGifCaptcha(130, 48, 4);
-
- // 设置字体
- chineseGifCaptcha.setFont(new Font("楷体", Font.PLAIN, 28)); // 有默认字体,可以不用设置
+### 5.3.字体设置
+内置字体:
- // 生成的验证码
- String code = chineseGifCaptcha.text();
-
- // 输出图片流
- chineseGifCaptcha.out(outputStream);
- }
-}
+ 字体 | 效果
+ :--- | :---
+ Captcha.FONT_1 | ![](https://s2.ax1x.com/2019/08/23/msMe6U.png)
+ Captcha.FONT_2 | ![](https://s2.ax1x.com/2019/08/23/msMAf0.png)
+ Captcha.FONT_3 | ![](https://s2.ax1x.com/2019/08/23/msMCwj.png)
+ Captcha.FONT_4 | ![](https://s2.ax1x.com/2019/08/23/msM9mQ.png)
+ Captcha.FONT_5 | ![](https://s2.ax1x.com/2019/08/23/msKz6S.png)
+ Captcha.FONT_6 | ![](https://s2.ax1x.com/2019/08/23/msKxl8.png)
+ Captcha.FONT_7 | ![](https://s2.ax1x.com/2019/08/23/msMPTs.png)
+ Captcha.FONT_8 | ![](https://s2.ax1x.com/2019/08/23/msMmXF.png)
+ Captcha.FONT_9 | ![](https://s2.ax1x.com/2019/08/23/msMVpV.png)
+ Captcha.FONT_10 | ![](https://s2.ax1x.com/2019/08/23/msMZlT.png)
+
+使用方法:
+```
+SpecCaptcha captcha = new SpecCaptcha(130, 48, 5);
+
+// 设置内置字体
+captcha.setFont(Captcha.FONT_1);
+
+// 设置系统字体
+captcha.setFont(new Font("楷体", Font.PLAIN, 28));
```
-### 4.5.前后端分离项目的使用
+### 5.4.输出base64编码
+```
+SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
+specCaptcha.toBase64();
- 分离项目建议不要存储在session中,存储在redis中。
+// 如果不想要base64的头部data:image/png;base64,
+specCaptcha.toBase64(""); // 加一个空的参数即可
+```
+### 5.5.输出到文件
+```
+FileOutputStream outputStream = new FileOutputStream(new File("C:/captcha.png"))
+SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
+specCaptcha.out(outputStream);
+```
-## 5.自定义效果
+---
-参考源代码中的SpecCaptcha和GifCaptcha继承Captcha即可。
+## 6.前后端分离项目的使用
+
+ 前后端分离项目建议不要存储在session中,存储在redis中,redis存储需要一个key,key一同返回给前端用于验证输入:
+```java
+@Controller
+public class CaptchaController {
+ @Autowired
+ private RedisUtil redisUtil;
+
+ @ResponseBody
+ @RequestMapping("/captcha")
+ public JsonResult captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
+ SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
+ String verCode = specCaptcha.text().toLowerCase();
+ String key = UUID.randomUUID().toString();
+ // 存入redis并设置过期时间为30分钟
+ redisUtil.setEx(key, verCode, 30, TimeUnit.MINUTES);
+ // 将key和base64返回给前端
+ return JsonResult.ok().put("key", key).put("image", specCaptcha.toBase64());
+ }
+
+ @ResponseBody
+ @PostMapping("/login")
+ public JsonResult login(String username,String password,String verCode,String verKey){
+ // 获取redis中的验证码
+ String redisCode = redisUtil.get(verKey);
+ // 判断验证码
+ if (verCode==null || !redisCode.equals(verCode.trim().toLowerCase())) {
+ return JsonResult.error("验证码不正确");
+ }
+ }
+}
+```
+前端使用ajax获取验证码:
+```html
+
+
+
+```
+
+> RedisUtil到这里获取[https://gitee.com/whvse/RedisUtil](https://gitee.com/whvse/RedisUtil)
+
+---
+
+## 7.自定义效果
+
+ 继承`Captcha`实现`out`方法,中文验证码可继承`ChineseCaptchaAbstract`,算术验证码可继承`ArithmeticCaptchaAbstract`。
+
+---
+
+## 8.更新日志
+
+- **2019-08-23 (v1.6.0)**
+ - 增加10种漂亮的内置字体,不依赖系统字体
+
+ - 增加算术验证码,运算位数可自由配置
+ - 增加输出base64编码的功能
+ - 增加贝塞尔曲线作为干扰线
+
+- **2018-08-09 (v1.5.0)**
+ - 增加纯大写字母、纯小写字母、数字和大写字母配置
+
+ - 增加中文验证码、中文gif验证码
+ - 增加抗锯齿效果,优化文字颜色
+ - 增加CaptchaUtil便于Web项目使用
+
+---
+
+## 9.推荐
+ **EasyWeb管系统模板**,一个开箱即用的后台模板,使用简单,功能丰富,包含ifram版和spa单页面版,[前往查看](https://easyweb.vip)。
+
+![](https://s2.ax1x.com/2019/08/23/msiO78.png)
diff --git a/pom.xml b/pom.xml
index 5070b53..7352603 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
org.wf
easy-captcha
- 1.5.0-RELEASE
+ 1.6.0-RELEASE
jar
EasyCaptcha
@@ -23,7 +23,7 @@
junit
junit
- 4.7
+ 4.12
test
diff --git a/src/main/java/com/wf/captcha/ArithmeticCaptcha.java b/src/main/java/com/wf/captcha/ArithmeticCaptcha.java
new file mode 100644
index 0000000..b29f851
--- /dev/null
+++ b/src/main/java/com/wf/captcha/ArithmeticCaptcha.java
@@ -0,0 +1,96 @@
+package com.wf.captcha;
+
+import com.wf.captcha.base.ArithmeticCaptchaAbstract;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.OutputStream;
+
+/**
+ * png格式验证码
+ * Created by 王帆 on 2018-07-27 上午 10:08.
+ */
+public class ArithmeticCaptcha extends ArithmeticCaptchaAbstract {
+
+ public ArithmeticCaptcha() {
+ }
+
+ public ArithmeticCaptcha(int width, int height) {
+ this();
+ setWidth(width);
+ setHeight(height);
+ }
+
+ public ArithmeticCaptcha(int width, int height, int len) {
+ this(width, height);
+ setLen(len);
+ }
+
+ public ArithmeticCaptcha(int width, int height, int len, Font font) {
+ this(width, height, len);
+ setFont(font);
+ }
+
+ /**
+ * 生成验证码
+ *
+ * @param out 输出流
+ * @return 是否成功
+ */
+ @Override
+ public boolean out(OutputStream out) {
+ checkAlpha();
+ return graphicsImage(getArithmeticString().toCharArray(), out);
+ }
+
+ @Override
+ public String toBase64() {
+ return toBase64("data:image/png;base64,");
+ }
+
+ /**
+ * 生成验证码图形
+ *
+ * @param strs 验证码
+ * @param out 输出流
+ * @return boolean
+ */
+ private boolean graphicsImage(char[] strs, OutputStream out) {
+ try {
+ BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
+ Graphics2D g2d = (Graphics2D) bi.getGraphics();
+ // 填充背景
+ g2d.setColor(Color.WHITE);
+ g2d.fillRect(0, 0, width, height);
+ // 抗锯齿
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ // 画干扰圆
+ drawOval(2, g2d);
+ // 画字符串
+ g2d.setFont(getFont());
+ FontMetrics fontMetrics = g2d.getFontMetrics();
+ int fW = width / strs.length; // 每一个字符所占的宽度
+ int fSp = (fW - (int) fontMetrics.getStringBounds("8", g2d).getWidth()) / 2; // 字符的左右边距
+ for (int i = 0; i < strs.length; i++) {
+ g2d.setColor(color());
+ int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
+ g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);
+ }
+ g2d.dispose();
+ ImageIO.write(bi, "png", out);
+ out.flush();
+ return true;
+ } catch (IOException e) {
+ e.printStackTrace();
+ } finally {
+ try {
+ out.close();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+ return false;
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/com/wf/captcha/ChineseCaptcha.java b/src/main/java/com/wf/captcha/ChineseCaptcha.java
index 2c3af93..a05cc83 100644
--- a/src/main/java/com/wf/captcha/ChineseCaptcha.java
+++ b/src/main/java/com/wf/captcha/ChineseCaptcha.java
@@ -38,10 +38,14 @@ public class ChineseCaptcha extends ChineseCaptchaAbstract {
*/
@Override
public boolean out(OutputStream out) {
- checkAlpha();
return graphicsImage(textChar(), out);
}
+ @Override
+ public String toBase64() {
+ return toBase64("data:image/png;base64,");
+ }
+
/**
* 生成验证码图形
*
@@ -50,54 +54,34 @@ public class ChineseCaptcha extends ChineseCaptchaAbstract {
* @return boolean
*/
private boolean graphicsImage(char[] strs, OutputStream out) {
- boolean ok;
try {
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
- Graphics2D g = (Graphics2D) bi.getGraphics();
- AlphaComposite ac3;
- int len = strs.length;
- g.setColor(Color.WHITE);
- g.fillRect(0, 0, width, height);
+ Graphics2D g2d = (Graphics2D) bi.getGraphics();
+ // 填充背景
+ g2d.setColor(Color.WHITE);
+ g2d.fillRect(0, 0, width, height);
// 抗锯齿
- g.setColor(color());
- Font font = getFont();
- g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- int hp = (height - font.getSize()) >> 1;
- int h = height - hp;
- int w = width / strs.length;
- int sp = (w - font.getSize()) / 2;
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ // 画干扰圆
+ drawOval(3, g2d);
+ // 画干扰线
+ g2d.setStroke(new BasicStroke(1.2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
+ drawBesselLine(1, g2d);
// 画字符串
- for (int i = 0; i < len; i++) {
- // 计算坐标
- int x = i * w + sp + num(-5, 5);
- int y = h + num(-5, 5);
- if (x < 5) {
- x = 5;
- }
- if (x + font.getSize() > width) {
- x = width - font.getSize();
- }
- if (y > height) {
- y = height;
- }
- 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);
+ g2d.setFont(getFont());
+ FontMetrics fontMetrics = g2d.getFontMetrics();
+ int fW = width / strs.length; // 每一个字符所占的宽度
+ int fSp = (fW - (int) fontMetrics.getStringBounds("王", g2d).getWidth()) / 2; // 字符的左右边距
+ for (int i = 0; i < strs.length; i++) {
+ g2d.setColor(color());
+ int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
+ g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);
}
- // 随机画干扰线
- g.setStroke(new BasicStroke(1.25f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
- ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f); // 指定透明度
- g.setComposite(ac3);
- drawLine(2, g.getColor(), g);
- // 画干扰圆圈
- drawOval(5, g.getColor(), g);
+ g2d.dispose();
ImageIO.write(bi, "png", out);
out.flush();
- ok = true;
+ return true;
} catch (IOException e) {
- ok = false;
e.printStackTrace();
} finally {
try {
@@ -106,6 +90,6 @@ public class ChineseCaptcha extends ChineseCaptchaAbstract {
e.printStackTrace();
}
}
- return ok;
+ return false;
}
}
diff --git a/src/main/java/com/wf/captcha/ChineseGifCaptcha.java b/src/main/java/com/wf/captcha/ChineseGifCaptcha.java
index 4cea9fd..7f2e35e 100644
--- a/src/main/java/com/wf/captcha/ChineseGifCaptcha.java
+++ b/src/main/java/com/wf/captcha/ChineseGifCaptcha.java
@@ -4,6 +4,7 @@ import com.wf.captcha.base.ChineseCaptchaAbstract;
import com.wf.captcha.utils.GifEncoder;
import java.awt.*;
+import java.awt.geom.CubicCurve2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
@@ -30,24 +31,39 @@ public class ChineseGifCaptcha extends ChineseCaptchaAbstract {
@Override
public boolean out(OutputStream os) {
- checkAlpha();
- boolean ok;
try {
- char[] rands = textChar(); // 获取验证码数组
+ char[] strs = textChar(); // 获取验证码数组
+ // 随机生成每个文字的颜色
+ Color fontColor[] = new Color[len];
+ for (int i = 0; i < len; i++) {
+ fontColor[i] = color();
+ }
+ // 随机生成贝塞尔曲线参数
+ int x1 = 5, y1 = num(5, height / 2);
+ int x2 = width - 5, y2 = num(height / 2, height - 5);
+ int ctrlx = num(width / 4, width / 4 * 3), ctrly = num(5, height - 5);
+ if (num(2) == 0) {
+ int ty = y1;
+ y1 = y2;
+ y2 = ty;
+ }
+ int ctrlx1 = num(width / 4, width / 4 * 3), ctrly1 = num(5, height - 5);
+ int[][] besselXY = new int[][]{{x1, y1}, {ctrlx, ctrly}, {ctrlx1, ctrly1}, {x2, y2}};
+ // 开始画gif每一帧
GifEncoder gifEncoder = new GifEncoder();
- gifEncoder.start(os);
gifEncoder.setQuality(180);
gifEncoder.setDelay(100);
gifEncoder.setRepeat(0);
- BufferedImage frame;
- Color fontcolor = color();
+ gifEncoder.start(os);
for (int i = 0; i < len; i++) {
- frame = graphicsImage(fontcolor, rands, i);
+ BufferedImage frame = graphicsImage(fontColor, strs, i, besselXY);
gifEncoder.addFrame(frame);
frame.flush();
}
gifEncoder.finish();
- ok = true;
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
} finally {
try {
os.close();
@@ -55,60 +71,53 @@ public class ChineseGifCaptcha extends ChineseCaptchaAbstract {
e.printStackTrace();
}
}
- return ok;
+ return false;
+ }
+
+ @Override
+ public String toBase64() {
+ return toBase64("data:image/gif;base64,");
}
/**
* 画随机码图
*
- * @param fontcolor 随机字体颜色
+ * @param fontColor 随机字体颜色
* @param strs 字符数组
- * @param flag 透明度使用
+ * @param flag 透明度
+ * @param besselXY 干扰线参数
* @return BufferedImage
*/
- private BufferedImage graphicsImage(Color fontcolor, char[] strs, int flag) {
+ private BufferedImage graphicsImage(Color[] fontColor, char[] strs, int flag, int[][] besselXY) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) image.getGraphics();
- g2d.setColor(Color.WHITE); // 填充背景颜色
+ // 填充背景颜色
+ g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height);
// 抗锯齿
- AlphaComposite ac3;
- g2d.setColor(fontcolor);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- // 画验证码
- Font font = getFont();
- int hp = (height - font.getSize()) >> 1;
- int h = height - hp;
- int w = width / strs.length;
- int sp = (w - font.getSize()) / 2;
- for (int i = 0; i < len; i++) {
- ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));
- g2d.setComposite(ac3);
- // 计算坐标
- int x = i * w + sp + num(-3, 3);
- int y = h + num(-3, 3);
- if (x < 0) {
- x = 0;
- }
- if (x + font.getSize() > width) {
- x = width - font.getSize();
- }
- if (y > height) {
- y = height;
- }
- 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);
- drawLine(1, g2d.getColor(), g2d);
// 画干扰圆圈
- drawOval(3, g2d.getColor(), g2d);
+ g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f * num(10))); // 设置透明度
+ drawOval(2, g2d);
+ // 画干扰线
+ g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f)); // 设置透明度
+ g2d.setStroke(new BasicStroke(1.2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
+ g2d.setColor(fontColor[0]);
+ CubicCurve2D shape = new CubicCurve2D.Double(besselXY[0][0], besselXY[0][1], besselXY[1][0], besselXY[1][1], besselXY[2][0], besselXY[2][1], besselXY[3][0], besselXY[3][1]);
+ g2d.draw(shape);
+ // 画验证码
+ g2d.setFont(getFont());
+ FontMetrics fontMetrics = g2d.getFontMetrics();
+ int fW = width / strs.length; // 每一个字符所占的宽度
+ int fSp = (fW - (int) fontMetrics.getStringBounds("W", g2d).getWidth()) / 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 fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
+ g2d.drawString(String.valueOf(strs[i]), i * fW + fSp - 3, fY - 3);
+ }
g2d.dispose();
return image;
}
diff --git a/src/main/java/com/wf/captcha/GifCaptcha.java b/src/main/java/com/wf/captcha/GifCaptcha.java
index 6d80c7c..5e59775 100644
--- a/src/main/java/com/wf/captcha/GifCaptcha.java
+++ b/src/main/java/com/wf/captcha/GifCaptcha.java
@@ -4,6 +4,9 @@ import com.wf.captcha.base.Captcha;
import com.wf.captcha.utils.GifEncoder;
import java.awt.*;
+import java.awt.geom.CubicCurve2D;
+import java.awt.geom.QuadCurve2D;
+import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
@@ -34,27 +37,39 @@ public class GifCaptcha extends Captcha {
@Override
public boolean out(OutputStream os) {
- checkAlpha();
- boolean ok;
try {
- char[] rands = textChar(); // 获取验证码数组
+ char[] strs = textChar(); // 获取验证码数组
+ // 随机生成每个文字的颜色
+ Color fontColor[] = new Color[len];
+ for (int i = 0; i < len; i++) {
+ fontColor[i] = color();
+ }
+ // 随机生成贝塞尔曲线参数
+ int x1 = 5, y1 = num(5, height / 2);
+ int x2 = width - 5, y2 = num(height / 2, height - 5);
+ int ctrlx = num(width / 4, width / 4 * 3), ctrly = num(5, height - 5);
+ if (num(2) == 0) {
+ int ty = y1;
+ y1 = y2;
+ y2 = ty;
+ }
+ int ctrlx1 = num(width / 4, width / 4 * 3), ctrly1 = num(5, height - 5);
+ int[][] besselXY = new int[][]{{x1, y1}, {ctrlx, ctrly}, {ctrlx1, ctrly1}, {x2, y2}};
+ // 开始画gif每一帧
GifEncoder gifEncoder = new GifEncoder();
- gifEncoder.start(os);
gifEncoder.setQuality(180);
gifEncoder.setDelay(100);
gifEncoder.setRepeat(0);
- BufferedImage frame;
- Color fontcolor[] = new Color[len];
+ gifEncoder.start(os);
for (int i = 0; i < len; i++) {
- fontcolor[i] = new Color(20 + num(110), 20 + num(110), 20 + num(110));
- }
- for (int i = 0; i < len; i++) {
- frame = graphicsImage(fontcolor, rands, i);
+ BufferedImage frame = graphicsImage(fontColor, strs, i, besselXY);
gifEncoder.addFrame(frame);
frame.flush();
}
gifEncoder.finish();
- ok = true;
+ return true;
+ } catch (Exception e) {
+ e.printStackTrace();
} finally {
try {
os.close();
@@ -62,18 +77,24 @@ public class GifCaptcha extends Captcha {
e.printStackTrace();
}
}
- return ok;
+ return false;
+ }
+
+ @Override
+ public String toBase64() {
+ return toBase64("data:image/gif;base64,");
}
/**
* 画随机码图
*
- * @param fontcolor 随机字体颜色
+ * @param fontColor 随机字体颜色
* @param strs 字符数组
- * @param flag 透明度使用
+ * @param flag 透明度
+ * @param besselXY 干扰线参数
* @return BufferedImage
*/
- private BufferedImage graphicsImage(Color[] fontcolor, char[] strs, int flag) {
+ private BufferedImage graphicsImage(Color[] fontColor, char[] strs, int flag, int[][] besselXY) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) image.getGraphics();
// 填充背景颜色
@@ -81,39 +102,27 @@ public class GifCaptcha extends Captcha {
g2d.fillRect(0, 0, width, height);
// 抗锯齿
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- g2d.setStroke(new BasicStroke(1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
// 画干扰圆圈
- drawOval(4, g2d);
- // 随机画干扰线
- drawLine(2, g2d);
+ g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f * num(10))); // 设置透明度
+ drawOval(2, g2d);
+ // 画干扰线
+ g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f)); // 设置透明度
+ g2d.setStroke(new BasicStroke(1.2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
+ g2d.setColor(fontColor[0]);
+ CubicCurve2D shape = new CubicCurve2D.Double(besselXY[0][0], besselXY[0][1], besselXY[1][0], besselXY[1][1], besselXY[2][0], besselXY[2][1], besselXY[3][0], besselXY[3][1]);
+ g2d.draw(shape);
// 画验证码
- Font font = getFont();
- int hp = (height - font.getSize()) >> 1;
- int h = height - hp;
- int w = width / strs.length;
- int sp = (w - font.getSize()) / 2;
+ g2d.setFont(getFont());
+ FontMetrics fontMetrics = g2d.getFontMetrics();
+ int fW = width / strs.length; // 每一个字符所占的宽度
+ int fSp = (fW - (int) fontMetrics.getStringBounds("W", g2d).getWidth()) / 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 + sp + num(3);
- int y = h - num(3, 6);
- // 调整溢出的字
- if (x < 8) {
- x = 8;
- }
- if (x + font.getSize() > width) {
- x = width - font.getSize();
- }
- if (y > height) {
- y = height;
- }
- 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.setColor(fontColor[i]);
+ int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
+ g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);
}
g2d.dispose();
return image;
diff --git a/src/main/java/com/wf/captcha/SpecCaptcha.java b/src/main/java/com/wf/captcha/SpecCaptcha.java
index 74abf82..2de05b9 100644
--- a/src/main/java/com/wf/captcha/SpecCaptcha.java
+++ b/src/main/java/com/wf/captcha/SpecCaptcha.java
@@ -45,6 +45,11 @@ public class SpecCaptcha extends Captcha {
return graphicsImage(textChar(), out);
}
+ @Override
+ public String toBase64() {
+ return toBase64("data:image/png;base64,");
+ }
+
/**
* 生成验证码图形
*
@@ -55,45 +60,28 @@ public class SpecCaptcha extends Captcha {
private boolean graphicsImage(char[] strs, OutputStream out) {
try {
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
- Graphics2D g = (Graphics2D) bi.getGraphics();
+ Graphics2D g2d = (Graphics2D) bi.getGraphics();
// 填充背景
- g.setColor(Color.WHITE);
- g.fillRect(0, 0, width, height);
+ g2d.setColor(Color.WHITE);
+ g2d.fillRect(0, 0, width, height);
// 抗锯齿
- g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- g.setStroke(new BasicStroke(1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
- // 随机画干扰线
- // drawLine(3, g);
- // 随机画干扰圆
- // drawOval(8, g);
- drawBesselLine(2, g);
+ g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ // 画干扰圆
+ drawOval(2, g2d);
+ // 画干扰线
+ g2d.setStroke(new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
+ drawBesselLine(1, g2d);
// 画字符串
- // AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f);// 指定透明度
- // g.setComposite(ac3);
- g.setFont(getFont());
- int fontSize = getFont().getSize();
- int fY = height - ((height - fontSize) >> 1); // 文字的纵坐标
+ g2d.setFont(getFont());
+ FontMetrics fontMetrics = g2d.getFontMetrics();
int fW = width / strs.length; // 每一个字符所占的宽度
- int fSp = (fW - fontSize) / 2; // 字符的左右边距
+ int fSp = (fW - (int) fontMetrics.getStringBounds("W", g2d).getWidth()) / 2; // 字符的左右边距
for (int i = 0; i < strs.length; i++) {
- g.setColor(color());
- // 计算坐标
- int x = i * fW + fSp;
- int y = fY/* - num(3, 6)*/;
- /*if (x < 8) {
- x = 8;
- }
- if (x + fontSize > width) {
- x = width - fontSize;
- }*/
- /*if (y > height) {
- y = height;
- }
- if (y - fontSize < 0) {
- y = fontSize;
- }*/
- g.drawString(String.valueOf(strs[i]), x, y);
+ g2d.setColor(color());
+ int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
+ g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);
}
+ g2d.dispose();
ImageIO.write(bi, "png", out);
out.flush();
return true;
diff --git a/src/main/java/com/wf/captcha/base/ArithmeticCaptchaAbstract.java b/src/main/java/com/wf/captcha/base/ArithmeticCaptchaAbstract.java
new file mode 100644
index 0000000..1d13f76
--- /dev/null
+++ b/src/main/java/com/wf/captcha/base/ArithmeticCaptchaAbstract.java
@@ -0,0 +1,55 @@
+package com.wf.captcha.base;
+
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptException;
+
+public abstract class ArithmeticCaptchaAbstract extends Captcha {
+ private String arithmeticString; // 计算公式
+
+ public ArithmeticCaptchaAbstract() {
+ setLen(2);
+ }
+
+ /**
+ * 生成随机验证码
+ *
+ * @return 验证码字符数组
+ */
+ @Override
+ protected char[] alphas() {
+ StringBuilder sb = new StringBuilder();
+ for (int i = 0; i < len; i++) {
+ sb.append(num(10));
+ if (i < len - 1) {
+ int type = num(1, 4);
+ if (type == 1) {
+ sb.append("+");
+ } else if (type == 2) {
+ sb.append("-");
+ } else if (type == 3) {
+ sb.append("x");
+ }
+ }
+ }
+ ScriptEngineManager manager = new ScriptEngineManager();
+ ScriptEngine engine = manager.getEngineByName("javascript");
+ try {
+ chars = String.valueOf(engine.eval(sb.toString().replaceAll("x", "*")));
+ } catch (ScriptException e) {
+ e.printStackTrace();
+ }
+ sb.append("=?");
+ arithmeticString = sb.toString();
+ return chars.toCharArray();
+ }
+
+ public String getArithmeticString() {
+ checkAlpha();
+ return arithmeticString;
+ }
+
+ public void setArithmeticString(String arithmeticString) {
+ this.arithmeticString = arithmeticString;
+ }
+}
diff --git a/src/main/java/com/wf/captcha/base/Captcha.java b/src/main/java/com/wf/captcha/base/Captcha.java
index c70b009..0d56679 100644
--- a/src/main/java/com/wf/captcha/base/Captcha.java
+++ b/src/main/java/com/wf/captcha/base/Captcha.java
@@ -1,8 +1,11 @@
package com.wf.captcha.base;
+import sun.misc.BASE64Encoder;
+
import java.awt.*;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.QuadCurve2D;
+import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream;
@@ -108,6 +111,20 @@ public abstract class Captcha extends Randoms {
*/
public abstract boolean out(OutputStream os);
+ public abstract String toBase64();
+
+ /**
+ * 输出base64编码
+ *
+ * @param type 编码头
+ * @return
+ */
+ public String toBase64(String type) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ out(outputStream);
+ return type + new BASE64Encoder().encode(outputStream.toByteArray());
+ }
+
/**
* 获取当前的验证码
*
@@ -156,7 +173,7 @@ public abstract class Captcha extends Randoms {
*/
public void drawLine(int num, Color color, Graphics2D g) {
for (int i = 0; i < num; i++) {
- g.setColor(color == null ? color(150, 250) : color);
+ g.setColor(color == null ? color() : color);
int x1 = num(-10, width - 10);
int y1 = num(5, height - 5);
int x2 = num(10, width + 10);
@@ -172,10 +189,7 @@ public abstract class Captcha extends Randoms {
* @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));
- }
+ drawOval(num, null, g);
}
/**
@@ -187,8 +201,9 @@ public abstract class Captcha extends Randoms {
*/
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));
+ g.setColor(color == null ? color() : color);
+ int w = 5 + num(10);
+ g.drawOval(num(width - 25), num(height - 15), w, w);
}
}
@@ -212,19 +227,20 @@ public abstract class Captcha extends Randoms {
public void drawBesselLine(int num, Color color, Graphics2D g) {
for (int i = 0; i < num; i++) {
g.setColor(color == null ? color() : color);
- int x1 = 5;
- int y1 = num(5, height - 5);
- int x2 = width - 5;
- int y2 = num(5, height - 5);
- int ctrlx = num(5, width - 5);
- int ctrly = num(5, height - 5);
+ int x1 = 5, y1 = num(5, height / 2);
+ int x2 = width - 5, y2 = num(height / 2, height - 5);
+ int ctrlx = num(width / 4, width / 4 * 3), ctrly = num(5, height - 5);
+ if (num(2) == 0) {
+ int ty = y1;
+ y1 = y2;
+ y2 = ty;
+ }
if (num(2) == 0) { // 二阶贝塞尔曲线
QuadCurve2D shape = new QuadCurve2D.Double();
shape.setCurve(x1, y1, ctrlx, ctrly, x2, y2);
g.draw(shape);
} else { // 三阶贝塞尔曲线
- int ctrlx1 = num(5, width - 5);
- int ctrly1 = num(5, height - 5);
+ int ctrlx1 = num(width / 4, width / 4 * 3), ctrly1 = num(5, height - 5);
CubicCurve2D shape = new CubicCurve2D.Double(x1, y1, ctrlx, ctrly, ctrlx1, ctrly1, x2, y2);
g.draw(shape);
}
@@ -247,7 +263,11 @@ public abstract class Captcha extends Randoms {
}
public void setFont(int font) throws IOException, FontFormatException {
- setFont(font, Font.BOLD, 32f);
+ setFont(font, 32f);
+ }
+
+ public void setFont(int font, float size) throws IOException, FontFormatException {
+ setFont(font, Font.BOLD, size);
}
public void setFont(int font, int style, float size) throws IOException, FontFormatException {
diff --git a/src/main/java/com/wf/captcha/base/ChineseCaptchaAbstract.java b/src/main/java/com/wf/captcha/base/ChineseCaptchaAbstract.java
index bd3a11a..f013edb 100644
--- a/src/main/java/com/wf/captcha/base/ChineseCaptchaAbstract.java
+++ b/src/main/java/com/wf/captcha/base/ChineseCaptchaAbstract.java
@@ -1,7 +1,5 @@
package com.wf.captcha.base;
-import com.wf.captcha.base.Captcha;
-
import java.awt.*;
public abstract class ChineseCaptchaAbstract extends Captcha {
@@ -37,16 +35,4 @@ 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);
- }
- }
}
diff --git a/src/main/java/com/wf/captcha/utils/CaptchaUtil.java b/src/main/java/com/wf/captcha/utils/CaptchaUtil.java
index 0c3595e..2f04b54 100644
--- a/src/main/java/com/wf/captcha/utils/CaptchaUtil.java
+++ b/src/main/java/com/wf/captcha/utils/CaptchaUtil.java
@@ -7,7 +7,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wf.captcha.base.Captcha;
-import com.wf.captcha.GifCaptcha;
import com.wf.captcha.SpecCaptcha;
/**
@@ -16,21 +15,9 @@ import com.wf.captcha.SpecCaptcha;
*/
public class CaptchaUtil {
private static final String SESSION_KEY = "captcha";
-
- /**
- * 验证验证码
- *
- * @param code 用户输入的验证码
- * @param request HttpServletRequest
- * @return 是否正确
- */
- public static boolean ver(String code, HttpServletRequest request) {
- if (code != null && !code.trim().isEmpty()) {
- String captcha = (String) request.getSession().getAttribute(SESSION_KEY);
- return code.trim().toLowerCase().equals(captcha);
- }
- return false;
- }
+ private static final int DEFAULT_LEN = 4; // 默认长度
+ private static final int DEFAULT_WIDTH = 130; // 默认宽度
+ private static final int DEFAULT_HEIGHT = 48; // 默认高度
/**
* 输出验证码
@@ -41,7 +28,7 @@ public class CaptchaUtil {
*/
public static void out(HttpServletRequest request, HttpServletResponse response)
throws IOException {
- out(5, request, response);
+ out(DEFAULT_LEN, request, response);
}
/**
@@ -54,21 +41,7 @@ public class CaptchaUtil {
*/
public static void out(int len, HttpServletRequest request, HttpServletResponse response)
throws IOException {
- out(130, 48, len, request, response);
- }
-
- /**
- * 输出验证码
- *
- * @param len 长度
- * @param font 字体
- * @param request HttpServletRequest
- * @param response HttpServletResponse
- * @throws IOException IO异常
- */
- public static void out(int len, Font font, HttpServletRequest request, HttpServletResponse response)
- throws IOException {
- out(130, 48, len, font, request, response);
+ out(DEFAULT_WIDTH, DEFAULT_HEIGHT, len, request, response);
}
/**
@@ -89,42 +62,14 @@ public class CaptchaUtil {
/**
* 输出验证码
*
- * @param width 宽度
- * @param height 高度
- * @param len 长度
* @param font 字体
* @param request HttpServletRequest
* @param response HttpServletResponse
* @throws IOException IO异常
*/
- public static void out(int width, int height, int len, Font font, HttpServletRequest request, HttpServletResponse response)
+ public static void out(Font font, HttpServletRequest request, HttpServletResponse response)
throws IOException {
- outCaptcha(width, height, len, font, 1, request, response);
- }
-
- /**
- * 输出验证码
- *
- * @param request HttpServletRequest
- * @param response HttpServletResponse
- * @throws IOException IO异常
- */
- public static void outPng(HttpServletRequest request, HttpServletResponse response)
- throws IOException {
- outPng(5, request, response);
- }
-
- /**
- * 输出验证码
- *
- * @param len 长度
- * @param request HttpServletRequest
- * @param response HttpServletResponse
- * @throws IOException IO异常
- */
- public static void outPng(int len, HttpServletRequest request, HttpServletResponse response)
- throws IOException {
- outPng(130, 48, len, request, response);
+ out(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_LEN, font, request, response);
}
/**
@@ -136,24 +81,9 @@ public class CaptchaUtil {
* @param response HttpServletResponse
* @throws IOException IO异常
*/
- public static void outPng(int len, Font font, HttpServletRequest request, HttpServletResponse response)
+ public static void out(int len, Font font, HttpServletRequest request, HttpServletResponse response)
throws IOException {
- outPng(130, 48, len, font, request, response);
- }
-
- /**
- * 输出验证码
- *
- * @param width 宽度
- * @param height 高度
- * @param len 长度
- * @param request HttpServletRequest
- * @param response HttpServletResponse
- * @throws IOException IO异常
- */
- public static void outPng(int width, int height, int len, HttpServletRequest request, HttpServletResponse response)
- throws IOException {
- outPng(width, height, len, null, request, response);
+ out(DEFAULT_WIDTH, DEFAULT_HEIGHT, len, font, request, response);
}
/**
@@ -167,39 +97,46 @@ public class CaptchaUtil {
* @param response HttpServletResponse
* @throws IOException IO异常
*/
- public static void outPng(int width, int height, int len, Font font, HttpServletRequest request, HttpServletResponse response)
+ public static void out(int width, int height, int len, Font font, HttpServletRequest request, HttpServletResponse response)
throws IOException {
- outCaptcha(width, height, len, font, 0, request, response);
+ SpecCaptcha specCaptcha = new SpecCaptcha(width, height, len);
+ if (font != null) {
+ specCaptcha.setFont(font);
+ }
+ out(specCaptcha, request, response);
}
+
/**
* 输出验证码
*
- * @param width 宽度
- * @param height 高度
- * @param len 长度
- * @param font 字体
- * @param cType 类型
+ * @param captcha Captcha
* @param request HttpServletRequest
* @param response HttpServletResponse
* @throws IOException IO异常
*/
- private static void outCaptcha(int width, int height, int len, Font font, int cType, HttpServletRequest request, HttpServletResponse response)
+ private static void out(Captcha captcha, HttpServletRequest request, HttpServletResponse response)
throws IOException {
setHeader(response);
- Captcha captcha = null;
- if (cType == 0) {
- captcha = new SpecCaptcha(width, height, len);
- } else if (cType == 1) {
- captcha = new GifCaptcha(width, height, len);
- }
- if (font != null) {
- captcha.setFont(font);
- }
request.getSession().setAttribute(SESSION_KEY, captcha.text().toLowerCase());
captcha.out(response.getOutputStream());
}
+ /**
+ * 验证验证码
+ *
+ * @param code 用户输入的验证码
+ * @param request HttpServletRequest
+ * @return 是否正确
+ */
+ public static boolean ver(String code, HttpServletRequest request) {
+ if (code != null) {
+ String captcha = (String) request.getSession().getAttribute(SESSION_KEY);
+ return code.trim().toLowerCase().equals(captcha);
+ }
+ return false;
+ }
+
/**
* 清除session中的验证码
*
diff --git a/src/test/java/com/wf/captcha/CaptchaTest.java b/src/test/java/com/wf/captcha/CaptchaTest.java
index bde5244..d4ee3d5 100644
--- a/src/test/java/com/wf/captcha/CaptchaTest.java
+++ b/src/test/java/com/wf/captcha/CaptchaTest.java
@@ -1,15 +1,9 @@
package com.wf.captcha;
-import com.wf.captcha.base.Captcha;
import org.junit.Test;
-import javax.imageio.ImageIO;
-import java.awt.*;
-import java.awt.geom.QuadCurve2D;
-import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
-import java.io.IOException;
/**
* 测试类
@@ -19,98 +13,59 @@ public class CaptchaTest {
@Test
public void test() throws Exception {
- for (int i = 0; i < 5; i++) {
+ /*for (int i = 0; i < 10; i++) {
SpecCaptcha specCaptcha = new SpecCaptcha();
- // specCaptcha.setCharType(Captcha.TYPE_ONLY_UPPER);
+ specCaptcha.setLen(4);
+ specCaptcha.setFont(i, 32f);
System.out.println(specCaptcha.text());
- // specCaptcha.setFont(Font.createFont(Font.TRUETYPE_FONT, new File(getClass().getResource("/actionj.ttf").getFile())).deriveFont(Font.BOLD, 32));
- specCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".png")));
- }
+ specCaptcha.out(new FileOutputStream(new File("C:/Java/aa" + i + ".png")));
+ }*/
}
@Test
public void testGIf() throws Exception {
- /*for (int i = 0; i < 5; i++) {
+ /*for (int i = 0; i < 10; i++) {
GifCaptcha gifCaptcha = new GifCaptcha();
+ gifCaptcha.setLen(5);
+ gifCaptcha.setFont(i, 32f);
System.out.println(gifCaptcha.text());
- gifCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".gif")));
+ gifCaptcha.out(new FileOutputStream(new File("C:/Java/aa" + i + ".gif")));
}*/
}
@Test
public void testHan() throws Exception {
- /*for (int i = 0; i < 5; i++) {
+ /*for (int i = 0; i < 10; i++) {
ChineseCaptcha chineseCaptcha = new ChineseCaptcha();
System.out.println(chineseCaptcha.text());
- chineseCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".png")));
+ chineseCaptcha.out(new FileOutputStream(new File("C:/Java/aa" + i + ".png")));
}*/
}
@Test
public void testGifHan() throws Exception {
- /*for (int i = 0; i < 5; i++) {
+ /*for (int i = 0; i < 10; i++) {
ChineseGifCaptcha chineseGifCaptcha = new ChineseGifCaptcha();
System.out.println(chineseGifCaptcha.text());
- chineseGifCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".gif")));
+ chineseGifCaptcha.out(new FileOutputStream(new File("C:/Java/aa" + i + ".gif")));
}*/
}
@Test
- public void test2() throws Exception {
- String[] colors = new String[]{"#8cc540", "#009f5d", "#019fa0", "#019fde", "#007cdc", "#887ddd", "#cd7bdd", "#ff5675", "#ff1244", "#ff8345", "#f8bd0b", "#d1d2d4"};
- String[] fonts = new String[]{"actionj.ttf", "epilog.ttf", "fresnel.ttf", "headache.ttf", "lexo.ttf", "prefix.ttf", "progbot.ttf", "ransom.ttf", "robot.ttf", "scandal.ttf"};
- int i = 0;
- for (String f : fonts) {
- i++;
- FileOutputStream out = new FileOutputStream(new File("D:/Java/aa" + i + ".png"));
- try {
- int width = 130, height = 48;
- BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
- Graphics2D g = (Graphics2D) bi.getGraphics();
- g.setColor(Color.WHITE);
- g.fillRect(0, 0, width, height);
- // 抗锯齿
- g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
- g.setStroke(new BasicStroke(1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
- // 画字符串
- float fontSize = 32f;
- Font font = Font.createFont(Font.TRUETYPE_FONT, new File(getClass().getResource("/" + f).getFile())).deriveFont(Font.BOLD, fontSize);
- g.setFont(font);
- char[] chars = "N4WbS".toCharArray();
- float sp = (width / chars.length - fontSize) / 2;
- int j = 0;
- for (char c : chars) {
- j++;
- g.setColor(Color.getColor(colors[j]));
- float x = sp * j + fontSize * (j - 1);
- float y = (height - fontSize) / 2 + fontSize;
- System.out.println(x + "-" + y);
- g.drawString(String.valueOf(c), x, y);
- }
- g.drawString("Hello", 8, 37);
- //
- QuadCurve2D shape = new QuadCurve2D.Double();
- shape.setCurve(8, 38, 38, 10, 120, 40);
- g.draw(shape);
- ImageIO.write(bi, "png", out);
- out.flush();
- } catch (IOException e) {
- e.printStackTrace();
- } finally {
- try {
- out.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
+ public void testArit() throws Exception {
+ /*for (int i = 0; i < 10; i++) {
+ ArithmeticCaptcha specCaptcha = new ArithmeticCaptcha();
+ specCaptcha.setLen(3);
+ specCaptcha.setFont(i, 28f);
+ System.out.println(specCaptcha.getArithmeticString() + " " + specCaptcha.text());
+ specCaptcha.out(new FileOutputStream(new File("C:/Java/aa" + i + ".png")));
+ }*/
}
@Test
- public void test3() throws Exception {
- String filePath = getClass().getResource("/actionj.ttf").getFile();
- System.out.println(filePath);
+ public void testBase64() throws Exception {
+ /*GifCaptcha specCaptcha = new GifCaptcha();
+ System.out.println(specCaptcha.toBase64(""));*/
}
-
}