增加内置字体、贝塞尔曲线、算术验证码、base64输出

pull/12/head
whvcse@foxmail.com 5 years ago
parent 366f54ea80
commit 8ebe5918c9

@ -5,48 +5,54 @@
## 1.简介 ## 1.简介
 Java图形验证码支持gif、中文、算术等类型可用于Java Web、JavaSE等项目。
  Java图形验证码支持gif验证码、中文验证码可用于Java Web、JavaSE项目。 ---
## 2.效果展示 ## 2.效果展示
**gif效果** ![验证码](https://s2.ax1x.com/2019/08/23/msFrE8.png)
  
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd30vgc2g303m01c0st.jpg) ![验证码](https://s2.ax1x.com/2019/08/23/msF0DP.png)
     
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd22ixh9g303m01c3yj.jpg) ![验证码](https://s2.ax1x.com/2019/08/23/msFwut.png)
<br/>
![验证码](https://s2.ax1x.com/2019/08/23/msFzVK.gif)
&emsp;&emsp; &emsp;&emsp;
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd2k0gjug303m01ct8t.jpg) ![验证码](https://s2.ax1x.com/2019/08/23/msFvb6.gif)
&emsp;&emsp;
![验证码](https://s2.ax1x.com/2019/08/23/msFXK1.gif)
**png效果** **算术类型**
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd09lqpaj303m01cwee.jpg) ![验证码](https://s2.ax1x.com/2019/08/23/mskKPg.png)
&emsp;&emsp; &emsp;&emsp;
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd0tj6nhj303m01ct8m.jpg) ![验证码](https://s2.ax1x.com/2019/08/23/msknIS.png)
&emsp;&emsp; &emsp;&emsp;
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd1cw3pcj303m01c0sn.jpg) ![验证码](https://s2.ax1x.com/2019/08/23/mskma8.png)
**中文验证码** **中文类型**
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovnvbgx6g303m01cjrc.jpg) ![验证码](https://s2.ax1x.com/2019/08/23/mskcdK.png)
&emsp;&emsp; &emsp;&emsp;
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovojp2gng303m01cq2w.jpg) ![验证码](https://s2.ax1x.com/2019/08/23/msk6Z6.png)
&emsp;&emsp; &emsp;&emsp;
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovp5u4c4g303m01cdft.jpg) ![验证码](https://s2.ax1x.com/2019/08/23/msksqx.png)
**内置字体:**
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovmfxg71j303m01cq2s.jpg) ![验证码](https://s2.ax1x.com/2019/08/23/msAVSJ.png)
&emsp;&emsp; &emsp;&emsp;
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovmy720dj303m01cq2s.jpg) ![验证码](https://s2.ax1x.com/2019/08/23/msAAW4.png)
&emsp;&emsp; &emsp;&emsp;
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovn68um6j303m01cglf.jpg) ![验证码](https://s2.ax1x.com/2019/08/23/msAkYF.png)
---
## 3.导入项目 ## 3.导入项目
### 2.1.gradle方式的引入 ### 3.1.gradle方式的引入
需要先在project的build.gradle中添加 需要先在project的build.gradle中添加
```text ```text
allprojects { allprojects {
@ -58,11 +64,11 @@ allprojects {
在项目的build.gradle中添加 在项目的build.gradle中添加
```text ```text
dependencies { 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中添加如下代码 在你的pom.xml中添加如下代码
```xml ```xml
<project> <project>
@ -77,33 +83,49 @@ dependencies {
<dependency> <dependency>
<groupId>com.github.whvcse</groupId> <groupId>com.github.whvcse</groupId>
<artifactId>EasyCaptcha</artifactId> <artifactId>EasyCaptcha</artifactId>
<version>1.5.0</version> <version>1.6.0</version>
</dependency> </dependency>
</dependencies> </dependencies>
</project> </project>
``` ```
### 2.3.jar包下载 ### 3.3.jar包下载
[EasyCaptcha-1.5.0.jar](https://gitee.com/whvse/EasyCaptcha/releases) [EasyCaptcha-1.6.0.jar](https://gitee.com/whvse/EasyCaptcha/releases)
maven导入jar包在项目根目录创建`libs`文件夹然后pom.xml添加如下 maven导入jar包在项目根目录创建`libs`文件夹然后pom.xml添加如下
``` ```
<dependency> <dependency>
<groupId>com.github.whvcse</groupId> <groupId>com.github.whvcse</groupId>
<artifactId>EasyCaptcha</artifactId> <artifactId>EasyCaptcha</artifactId>
<version>1.5.0</version> <version>1.6.0</version>
<systemPath>${basedir}/libs/EasyCaptcha-1.5.0.jar</systemPath> <systemPath>${basedir}/libs/EasyCaptcha-1.6.0.jar</systemPath>
</dependency> </dependency>
``` ```
--- ---
## 4.使用方法
### 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
<img src="/captcha" width="130px" height="48px" />
```
## 3.使用方法 > 不要忘了把`/captcha`路径排除登录拦截比如shiro的拦截。
### 3.1.快速使用 ### 4.2.在servlet中使用
1.在web.xml里面加入如下配置 web.xml中配置servlet
```xml ```xml
<web-app> <web-app>
<!-- 图形验证码servlet --> <!-- 图形验证码servlet -->
@ -113,163 +135,130 @@ maven导入jar包在项目根目录创建`libs`文件夹然后pom.xml添
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>CaptchaServlet</servlet-name> <servlet-name>CaptchaServlet</servlet-name>
   <url-pattern>/images/captcha</url-pattern>    <url-pattern>/captcha</url-pattern>
</servlet-mapping> </servlet-mapping>
</web-app> </web-app>
``` ```
2.前端代码 前端html代码
```html
<img src="/images/captcha" />
```
### 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 ```html
<img src="/images/captcha" /> <img src="/captcha" width="130px" height="48px" />
``` ```
### 3.3.判断验证码是否正确 ### 4.3.判断验证码是否正确
```java ```java
@Controller @Controller
public class LoginController { public class LoginController {
@PostMapping("/login") @PostMapping("/login")
public JsonResult login(String username,String password,String code){ public JsonResult login(String username,String password,String verCode){
if (!CaptchaUtil.ver(verCode, request)) {
if (!CaptchaUtil.ver(code, request)) { CaptchaUtil.clear(request); // 清除session中的验证码
CaptchaUtil.clear(request);
return JsonResult.error("验证码不正确"); return JsonResult.error("验证码不正确");
} }
} }
} }
``` ```
### 3.4.设置宽高和位数 ### 4.4.设置宽高和位数
```java ```java
@Controller @Controller
public class MainController { public class CaptchaController {
@RequestMapping("/images/captcha") @RequestMapping("/captcha")
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception { public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 设置位数 // 设置位数
CaptchaUtil.out(5, request, response); CaptchaUtil.out(5, request, response);
// 设置宽、高、位数 // 设置宽、高、位数
CaptchaUtil.out(130, 48, 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.不使用工具类 ### 4.5.不使用工具类
&emsp;CaptchaUtil封装了输出验证码、存session、判断验证码等功能也可以不使用此工具类
&emsp;&emsp;CaptchaUtil是为了简化操作封装了生成验证码、存session、判断验证码等功能。CaptchaUtil使用的GifCaptcha
生成的字母数字混合的gif验证码如果需要设置更多的参数请参照如下操作使用
```java ```java
@Controller @Controller
public class MainController { public class CaptchaController {
@RequestMapping("/images/captcha") @RequestMapping("/captcha")
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception { 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 // 验证码存入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") @PostMapping("/login")
public JsonResult login(String username,String password,String code){ public JsonResult login(String username,String password,String verCode){
// 获取session中的验证码 // 获取session中的验证码
String sessionCode = request.getSession().getAttribute("captcha"); 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("验证码不正确"); return JsonResult.error("验证码不正确");
} }
} }
} }
``` ```
## 4.更多设置 ## 5.更多设置
### 4.1.使用Gif验证码 ### 5.1.验证码类型
```java ```java
public class Test { public class Test {
public static void main(String[] args) { 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(); // 获取验证码的字符数组
// 三个参数分别为宽、高、位数 // gif类型
GifCaptcha gifCaptcha = new GifCaptcha(130, 48, 5); GifCaptcha captcha = new GifCaptcha(130, 48, 5);
// 设置字体 // 中文类型
gifCaptcha.setFont(new Font("Verdana", Font.PLAIN, 32)); // 有默认字体,可以不用设置 ChineseCaptcha captcha = new ChineseCaptcha(130, 48, 5);
// 设置类型,纯数字、纯字母、字母数字混合 // 中文gif类型
gifCaptcha.setCharType(Captcha.TYPE_ONLY_NUMBER); 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
// 输出图片流 captcha.out(outputStream); // 输出验证码
gifCaptcha.out(outputStream);
} }
} }
``` ```
### 4.2.使用png验证码 > 注意:<br/>
> &emsp;算术验证码的len表示是几位数运算而其他验证码的len表示验证码的位数算术验证码的text()表示的是公式的结果,
```java > 对于算术验证码你应该把公式的结果存储session而不是公式。
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_ONLY_LOWER | 纯小写字母
TYPE_NUM_AND_UPPER | 数字和大写字母 TYPE_NUM_AND_UPPER | 数字和大写字母
使用方法:
```
SpecCaptcha captcha = new SpecCaptcha(130, 48, 5);
captcha.setCharType(Captcha.TYPE_ONLY_NUMBER);
```
### 4.4.中文验证码 > 只有`SpecCaptcha`和`GifCaptcha`设置才有效果。
中文png验证码 ### 5.3.字体设置
内置字体:
```java 字体 | 效果
public class Test { :--- | :---
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);
public static void main(String[] args) { // 设置内置字体
OutputStream outputStream = new FileOutputStream(new File("D:/a/aa.png")); captcha.setFont(Captcha.FONT_1);
// 三个参数分别为宽、高、位数 // 设置系统字体
ChineseCaptcha chineseCaptcha = new ChineseCaptcha(130, 48, 4); captcha.setFont(new Font("楷体", Font.PLAIN, 28));
```
// 设置字体 ### 5.4.输出base64编码
chineseCaptcha.setFont(new Font("楷体", Font.PLAIN, 28)); // 有默认字体,可以不用设置 ```
SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
specCaptcha.toBase64();
// 生成的验证码 // 如果不想要base64的头部data:image/png;base64,
String code = chineseCaptcha.text(); specCaptcha.toBase64(""); // 加一个空的参数即可
```
// 输出图片流 ### 5.5.输出到文件
chineseCaptcha.out(outputStream); ```
FileOutputStream outputStream = new FileOutputStream(new File("C:/captcha.png"))
SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
specCaptcha.out(outputStream);
```
---
## 6.前后端分离项目的使用
&emsp;前后端分离项目建议不要存储在session中存储在redis中redis存储需要一个keykey一同返回给前端用于验证输入
```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
<img id="verImg" />
<script>
var verKey;
// 获取验证码
$.get('/captcha', function(res) {
verKey = res.key;
$('#verImg').attr('src', res.image);
},'json');
// 登录
$.post('/login', {
verKey: verKey,
verCode: '8u6h',
username: 'admin'
password: 'admin'
}, function(res) {
console.log(res);
}, 'json');
</script>
``` ```
中文gif验证码 > RedisUtil到这里获取[https://gitee.com/whvse/RedisUtil](https://gitee.com/whvse/RedisUtil)
```java ---
public class Test {
public static void main(String[] args) { ## 7.自定义效果
OutputStream outputStream = new FileOutputStream(new File("D:/a/aa.png"));
// 三个参数分别为宽、高、位数 &emsp;继承`Captcha`实现`out`方法,中文验证码可继承`ChineseCaptchaAbstract`,算术验证码可继承`ArithmeticCaptchaAbstract`。
ChineseGifCaptcha chineseGifCaptcha = new ChineseGifCaptcha(130, 48, 4);
// 设置字体 ---
chineseGifCaptcha.setFont(new Font("楷体", Font.PLAIN, 28)); // 有默认字体,可以不用设置
// 生成的验证码 ## 8.更新日志
String code = chineseGifCaptcha.text();
// 输出图片流 - **2019-08-23 (v1.6.0)**
chineseGifCaptcha.out(outputStream); - 增加10种漂亮的内置字体不依赖系统字体
}
} - 增加算术验证码,运算位数可自由配置
``` - 增加输出base64编码的功能
- 增加贝塞尔曲线作为干扰线
### 4.5.前后端分离项目的使用 - **2018-08-09 (v1.5.0)**
- 增加纯大写字母、纯小写字母、数字和大写字母配置
&emsp;&emsp;分离项目建议不要存储在session中存储在redis中。 - 增加中文验证码、中文gif验证码
- 增加抗锯齿效果,优化文字颜色
- 增加CaptchaUtil便于Web项目使用
---
## 5.自定义效果 ## 9.推荐
&emsp;**EasyWeb管系统模板**一个开箱即用的后台模板使用简单功能丰富包含ifram版和spa单页面版[前往查看](https://easyweb.vip)。
参考源代码中的SpecCaptcha和GifCaptcha继承Captcha即可。 ![](https://s2.ax1x.com/2019/08/23/msiO78.png)

@ -5,7 +5,7 @@
<groupId>org.wf</groupId> <groupId>org.wf</groupId>
<artifactId>easy-captcha</artifactId> <artifactId>easy-captcha</artifactId>
<version>1.5.0-RELEASE</version> <version>1.6.0-RELEASE</version>
<packaging>jar</packaging> <packaging>jar</packaging>
<name>EasyCaptcha</name> <name>EasyCaptcha</name>
@ -23,7 +23,7 @@
<dependency> <dependency>
<groupId>junit</groupId> <groupId>junit</groupId>
<artifactId>junit</artifactId> <artifactId>junit</artifactId>
<version>4.7</version> <version>4.12</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
</dependencies> </dependencies>

@ -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;
}
}

@ -38,10 +38,14 @@ public class ChineseCaptcha extends ChineseCaptchaAbstract {
*/ */
@Override @Override
public boolean out(OutputStream out) { public boolean out(OutputStream out) {
checkAlpha();
return graphicsImage(textChar(), out); 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 * @return boolean
*/ */
private boolean graphicsImage(char[] strs, OutputStream out) { private boolean graphicsImage(char[] strs, OutputStream out) {
boolean ok;
try { try {
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) bi.getGraphics(); Graphics2D g2d = (Graphics2D) bi.getGraphics();
AlphaComposite ac3; // 填充背景
int len = strs.length; g2d.setColor(Color.WHITE);
g.setColor(Color.WHITE); g2d.fillRect(0, 0, width, height);
g.fillRect(0, 0, width, height);
// 抗锯齿 // 抗锯齿
g.setColor(color()); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Font font = getFont(); // 画干扰圆
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); drawOval(3, g2d);
int hp = (height - font.getSize()) >> 1; // 画干扰线
int h = height - hp; g2d.setStroke(new BasicStroke(1.2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
int w = width / strs.length; drawBesselLine(1, g2d);
int sp = (w - font.getSize()) / 2;
// 画字符串 // 画字符串
for (int i = 0; i < len; i++) { g2d.setFont(getFont());
// 计算坐标 FontMetrics fontMetrics = g2d.getFontMetrics();
int x = i * w + sp + num(-5, 5); int fW = width / strs.length; // 每一个字符所占的宽度
int y = h + num(-5, 5); int fSp = (fW - (int) fontMetrics.getStringBounds("王", g2d).getWidth()) / 2; // 字符的左右边距
if (x < 5) { for (int i = 0; i < strs.length; i++) {
x = 5; g2d.setColor(color());
} int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
if (x + font.getSize() > width) { g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);
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.dispose();
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);
ImageIO.write(bi, "png", out); ImageIO.write(bi, "png", out);
out.flush(); out.flush();
ok = true; return true;
} catch (IOException e) { } catch (IOException e) {
ok = false;
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
try { try {
@ -106,6 +90,6 @@ public class ChineseCaptcha extends ChineseCaptchaAbstract {
e.printStackTrace(); e.printStackTrace();
} }
} }
return ok; return false;
} }
} }

@ -4,6 +4,7 @@ import com.wf.captcha.base.ChineseCaptchaAbstract;
import com.wf.captcha.utils.GifEncoder; import com.wf.captcha.utils.GifEncoder;
import java.awt.*; import java.awt.*;
import java.awt.geom.CubicCurve2D;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
@ -30,24 +31,39 @@ public class ChineseGifCaptcha extends ChineseCaptchaAbstract {
@Override @Override
public boolean out(OutputStream os) { public boolean out(OutputStream os) {
checkAlpha();
boolean ok;
try { 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 gifEncoder = new GifEncoder();
gifEncoder.start(os);
gifEncoder.setQuality(180); gifEncoder.setQuality(180);
gifEncoder.setDelay(100); gifEncoder.setDelay(100);
gifEncoder.setRepeat(0); gifEncoder.setRepeat(0);
BufferedImage frame; gifEncoder.start(os);
Color fontcolor = color();
for (int i = 0; i < len; i++) { for (int i = 0; i < len; i++) {
frame = graphicsImage(fontcolor, rands, i); BufferedImage frame = graphicsImage(fontColor, strs, i, besselXY);
gifEncoder.addFrame(frame); gifEncoder.addFrame(frame);
frame.flush(); frame.flush();
} }
gifEncoder.finish(); gifEncoder.finish();
ok = true; return true;
} catch (Exception e) {
e.printStackTrace();
} finally { } finally {
try { try {
os.close(); os.close();
@ -55,60 +71,53 @@ public class ChineseGifCaptcha extends ChineseCaptchaAbstract {
e.printStackTrace(); e.printStackTrace();
} }
} }
return ok; return false;
}
@Override
public String toBase64() {
return toBase64("data:image/gif;base64,");
} }
/** /**
* *
* *
* @param fontcolor * @param fontColor
* @param strs * @param strs
* @param flag 使 * @param flag
* @param besselXY 线
* @return BufferedImage * @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); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) image.getGraphics(); Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setColor(Color.WHITE); // 填充背景颜色 // 填充背景颜色
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height); g2d.fillRect(0, 0, width, height);
// 抗锯齿 // 抗锯齿
AlphaComposite ac3;
g2d.setColor(fontcolor);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 画干扰圆圈
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(); g2d.setFont(getFont());
int hp = (height - font.getSize()) >> 1; FontMetrics fontMetrics = g2d.getFontMetrics();
int h = height - hp; int fW = width / strs.length; // 每一个字符所占的宽度
int w = width / strs.length; int fSp = (fW - (int) fontMetrics.getStringBounds("W", g2d).getWidth()) / 2; // 字符的左右边距
int sp = (w - font.getSize()) / 2; for (int i = 0; i < strs.length; i++) {
for (int i = 0; i < len; i++) { // 设置透明度
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]);
int x = i * w + sp + num(-3, 3); int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
int y = h + num(-3, 3); g2d.drawString(String.valueOf(strs[i]), i * fW + fSp - 3, fY - 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.dispose(); g2d.dispose();
return image; return image;
} }

@ -4,6 +4,9 @@ import com.wf.captcha.base.Captcha;
import com.wf.captcha.utils.GifEncoder; import com.wf.captcha.utils.GifEncoder;
import java.awt.*; 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.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
@ -34,27 +37,39 @@ public class GifCaptcha extends Captcha {
@Override @Override
public boolean out(OutputStream os) { public boolean out(OutputStream os) {
checkAlpha();
boolean ok;
try { 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 gifEncoder = new GifEncoder();
gifEncoder.start(os);
gifEncoder.setQuality(180); gifEncoder.setQuality(180);
gifEncoder.setDelay(100); gifEncoder.setDelay(100);
gifEncoder.setRepeat(0); gifEncoder.setRepeat(0);
BufferedImage frame; gifEncoder.start(os);
Color fontcolor[] = new Color[len];
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++) { for (int i = 0; i < len; i++) {
frame = graphicsImage(fontcolor, rands, i); BufferedImage frame = graphicsImage(fontColor, strs, i, besselXY);
gifEncoder.addFrame(frame); gifEncoder.addFrame(frame);
frame.flush(); frame.flush();
} }
gifEncoder.finish(); gifEncoder.finish();
ok = true; return true;
} catch (Exception e) {
e.printStackTrace();
} finally { } finally {
try { try {
os.close(); os.close();
@ -62,18 +77,24 @@ public class GifCaptcha extends Captcha {
e.printStackTrace(); e.printStackTrace();
} }
} }
return ok; return false;
}
@Override
public String toBase64() {
return toBase64("data:image/gif;base64,");
} }
/** /**
* *
* *
* @param fontcolor * @param fontColor
* @param strs * @param strs
* @param flag 使 * @param flag
* @param besselXY 线
* @return BufferedImage * @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); BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) image.getGraphics(); Graphics2D g2d = (Graphics2D) image.getGraphics();
// 填充背景颜色 // 填充背景颜色
@ -81,39 +102,27 @@ public class GifCaptcha extends Captcha {
g2d.fillRect(0, 0, width, height); g2d.fillRect(0, 0, width, height);
// 抗锯齿 // 抗锯齿
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); g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f * num(10))); // 设置透明度
// 随机画干扰线 drawOval(2, g2d);
drawLine(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(); g2d.setFont(getFont());
int hp = (height - font.getSize()) >> 1; FontMetrics fontMetrics = g2d.getFontMetrics();
int h = height - hp; int fW = width / strs.length; // 每一个字符所占的宽度
int w = width / strs.length; int fSp = (fW - (int) fontMetrics.getStringBounds("W", g2d).getWidth()) / 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 fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
int x = i * w + sp + num(3); g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 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.dispose(); g2d.dispose();
return image; return image;

@ -45,6 +45,11 @@ public class SpecCaptcha extends Captcha {
return graphicsImage(textChar(), out); 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) { private boolean graphicsImage(char[] strs, OutputStream out) {
try { try {
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g = (Graphics2D) bi.getGraphics(); Graphics2D g2d = (Graphics2D) bi.getGraphics();
// 填充背景 // 填充背景
g.setColor(Color.WHITE); g2d.setColor(Color.WHITE);
g.fillRect(0, 0, width, height); g2d.fillRect(0, 0, width, height);
// 抗锯齿 // 抗锯齿
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setStroke(new BasicStroke(1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); // 画干扰圆
// 随机画干扰线 drawOval(2, g2d);
// drawLine(3, g); // 画干扰线
// 随机画干扰圆 g2d.setStroke(new BasicStroke(2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
// drawOval(8, g); drawBesselLine(1, g2d);
drawBesselLine(2, g);
// 画字符串 // 画字符串
// AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f);// 指定透明度 g2d.setFont(getFont());
// g.setComposite(ac3); FontMetrics fontMetrics = g2d.getFontMetrics();
g.setFont(getFont());
int fontSize = getFont().getSize();
int fY = height - ((height - fontSize) >> 1); // 文字的纵坐标
int fW = width / strs.length; // 每一个字符所占的宽度 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++) { for (int i = 0; i < strs.length; i++) {
g.setColor(color()); g2d.setColor(color());
// 计算坐标 int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
int x = i * fW + fSp; g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);
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.dispose();
ImageIO.write(bi, "png", out); ImageIO.write(bi, "png", out);
out.flush(); out.flush();
return true; return true;

@ -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;
}
}

@ -1,8 +1,11 @@
package com.wf.captcha.base; package com.wf.captcha.base;
import sun.misc.BASE64Encoder;
import java.awt.*; import java.awt.*;
import java.awt.geom.CubicCurve2D; import java.awt.geom.CubicCurve2D;
import java.awt.geom.QuadCurve2D; import java.awt.geom.QuadCurve2D;
import java.io.ByteArrayOutputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
@ -108,6 +111,20 @@ public abstract class Captcha extends Randoms {
*/ */
public abstract boolean out(OutputStream os); 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) { public void drawLine(int num, Color color, Graphics2D g) {
for (int i = 0; i < num; i++) { 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 x1 = num(-10, width - 10);
int y1 = num(5, height - 5); int y1 = num(5, height - 5);
int x2 = num(10, width + 10); int x2 = num(10, width + 10);
@ -172,10 +189,7 @@ public abstract class Captcha extends Randoms {
* @param g Graphics2D * @param g Graphics2D
*/ */
public void drawOval(int num, Graphics2D g) { public void drawOval(int num, Graphics2D g) {
for (int i = 0; i < num; i++) { drawOval(num, null, g);
g.setColor(color(100, 250));
g.drawOval(num(width), num(height), 10 + num(20), 10 + num(20));
}
} }
/** /**
@ -187,8 +201,9 @@ public abstract class Captcha extends Randoms {
*/ */
public void drawOval(int num, Color color, Graphics2D g) { public void drawOval(int num, Color color, Graphics2D g) {
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
g.setColor(color == null ? color(100, 250) : color); g.setColor(color == null ? color() : color);
g.drawOval(num(width), num(height), 10 + num(20), 10 + num(20)); 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) { public void drawBesselLine(int num, Color color, Graphics2D g) {
for (int i = 0; i < num; i++) { for (int i = 0; i < num; i++) {
g.setColor(color == null ? color() : color); g.setColor(color == null ? color() : color);
int x1 = 5; int x1 = 5, y1 = num(5, height / 2);
int y1 = num(5, height - 5); int x2 = width - 5, y2 = num(height / 2, height - 5);
int x2 = width - 5; int ctrlx = num(width / 4, width / 4 * 3), ctrly = num(5, height - 5);
int y2 = num(5, height - 5); if (num(2) == 0) {
int ctrlx = num(5, width - 5); int ty = y1;
int ctrly = num(5, height - 5); y1 = y2;
y2 = ty;
}
if (num(2) == 0) { // 二阶贝塞尔曲线 if (num(2) == 0) { // 二阶贝塞尔曲线
QuadCurve2D shape = new QuadCurve2D.Double(); QuadCurve2D shape = new QuadCurve2D.Double();
shape.setCurve(x1, y1, ctrlx, ctrly, x2, y2); shape.setCurve(x1, y1, ctrlx, ctrly, x2, y2);
g.draw(shape); g.draw(shape);
} else { // 三阶贝塞尔曲线 } else { // 三阶贝塞尔曲线
int ctrlx1 = num(5, width - 5); int ctrlx1 = num(width / 4, width / 4 * 3), ctrly1 = num(5, height - 5);
int ctrly1 = num(5, height - 5);
CubicCurve2D shape = new CubicCurve2D.Double(x1, y1, ctrlx, ctrly, ctrlx1, ctrly1, x2, y2); CubicCurve2D shape = new CubicCurve2D.Double(x1, y1, ctrlx, ctrly, ctrlx1, ctrly1, x2, y2);
g.draw(shape); g.draw(shape);
} }
@ -247,7 +263,11 @@ public abstract class Captcha extends Randoms {
} }
public void setFont(int font) throws IOException, FontFormatException { 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 { public void setFont(int font, int style, float size) throws IOException, FontFormatException {

@ -1,7 +1,5 @@
package com.wf.captcha.base; package com.wf.captcha.base;
import com.wf.captcha.base.Captcha;
import java.awt.*; import java.awt.*;
public abstract class ChineseCaptchaAbstract extends Captcha { public abstract class ChineseCaptchaAbstract extends Captcha {
@ -37,16 +35,4 @@ 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);
}
}
} }

@ -7,7 +7,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.wf.captcha.base.Captcha; import com.wf.captcha.base.Captcha;
import com.wf.captcha.GifCaptcha;
import com.wf.captcha.SpecCaptcha; import com.wf.captcha.SpecCaptcha;
/** /**
@ -16,21 +15,9 @@ import com.wf.captcha.SpecCaptcha;
*/ */
public class CaptchaUtil { public class CaptchaUtil {
private static final String SESSION_KEY = "captcha"; private static final String SESSION_KEY = "captcha";
private static final int DEFAULT_LEN = 4; // 默认长度
/** private static final int DEFAULT_WIDTH = 130; // 默认宽度
* private static final int DEFAULT_HEIGHT = 48; // 默认高度
*
* @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;
}
/** /**
* *
@ -41,7 +28,7 @@ public class CaptchaUtil {
*/ */
public static void out(HttpServletRequest request, HttpServletResponse response) public static void out(HttpServletRequest request, HttpServletResponse response)
throws IOException { 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) public static void out(int len, HttpServletRequest request, HttpServletResponse response)
throws IOException { throws IOException {
out(130, 48, len, request, response); out(DEFAULT_WIDTH, DEFAULT_HEIGHT, 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);
} }
/** /**
@ -89,42 +62,14 @@ public class CaptchaUtil {
/** /**
* *
* *
* @param width
* @param height
* @param len
* @param font * @param font
* @param request HttpServletRequest * @param request HttpServletRequest
* @param response HttpServletResponse * @param response HttpServletResponse
* @throws IOException IO * @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 { throws IOException {
outCaptcha(width, height, len, font, 1, request, response); out(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_LEN, font, 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);
} }
/** /**
@ -136,9 +81,9 @@ public class CaptchaUtil {
* @param response HttpServletResponse * @param response HttpServletResponse
* @throws IOException IO * @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 { throws IOException {
outPng(130, 48, len, font, request, response); out(DEFAULT_WIDTH, DEFAULT_HEIGHT, len, font, request, response);
} }
/** /**
@ -147,57 +92,49 @@ public class CaptchaUtil {
* @param width * @param width
* @param height * @param height
* @param len * @param len
* @param font
* @param request HttpServletRequest * @param request HttpServletRequest
* @param response HttpServletResponse * @param response HttpServletResponse
* @throws IOException IO * @throws IOException IO
*/ */
public static void outPng(int width, int height, int len, HttpServletRequest request, HttpServletResponse response) public static void out(int width, int height, int len, Font font, HttpServletRequest request, HttpServletResponse response)
throws IOException { throws IOException {
outPng(width, height, len, null, request, response); SpecCaptcha specCaptcha = new SpecCaptcha(width, height, len);
if (font != null) {
specCaptcha.setFont(font);
}
out(specCaptcha, request, response);
} }
/** /**
* *
* *
* @param width * @param captcha Captcha
* @param height
* @param len
* @param font
* @param request HttpServletRequest * @param request HttpServletRequest
* @param response HttpServletResponse * @param response HttpServletResponse
* @throws IOException IO * @throws IOException IO
*/ */
public static void outPng(int width, int height, int len, Font font, HttpServletRequest request, HttpServletResponse response) private static void out(Captcha captcha, HttpServletRequest request, HttpServletResponse response)
throws IOException { throws IOException {
outCaptcha(width, height, len, font, 0, request, response); setHeader(response);
request.getSession().setAttribute(SESSION_KEY, captcha.text().toLowerCase());
captcha.out(response.getOutputStream());
} }
/** /**
* *
* *
* @param width * @param code
* @param height
* @param len
* @param font
* @param cType
* @param request HttpServletRequest * @param request HttpServletRequest
* @param response HttpServletResponse * @return
* @throws IOException IO
*/ */
private static void outCaptcha(int width, int height, int len, Font font, int cType, HttpServletRequest request, HttpServletResponse response) public static boolean ver(String code, HttpServletRequest request) {
throws IOException { if (code != null) {
setHeader(response); String captcha = (String) request.getSession().getAttribute(SESSION_KEY);
Captcha captcha = null; return code.trim().toLowerCase().equals(captcha);
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()); return false;
captcha.out(response.getOutputStream());
} }
/** /**

@ -1,15 +1,9 @@
package com.wf.captcha; package com.wf.captcha;
import com.wf.captcha.base.Captcha;
import org.junit.Test; 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.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException;
/** /**
* *
@ -19,98 +13,59 @@ 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 < 10; i++) {
SpecCaptcha specCaptcha = new SpecCaptcha(); SpecCaptcha specCaptcha = new SpecCaptcha();
// specCaptcha.setCharType(Captcha.TYPE_ONLY_UPPER); specCaptcha.setLen(4);
specCaptcha.setFont(i, 32f);
System.out.println(specCaptcha.text()); 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("C:/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 < 10; i++) {
GifCaptcha gifCaptcha = new GifCaptcha(); GifCaptcha gifCaptcha = new GifCaptcha();
gifCaptcha.setLen(5);
gifCaptcha.setFont(i, 32f);
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("C:/Java/aa" + i + ".gif")));
}*/ }*/
} }
@Test @Test
public void testHan() throws Exception { public void testHan() throws Exception {
/*for (int i = 0; i < 5; i++) { /*for (int i = 0; i < 10; i++) {
ChineseCaptcha chineseCaptcha = new ChineseCaptcha(); ChineseCaptcha chineseCaptcha = new ChineseCaptcha();
System.out.println(chineseCaptcha.text()); 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 @Test
public void testGifHan() throws Exception { public void testGifHan() throws Exception {
/*for (int i = 0; i < 5; i++) { /*for (int i = 0; i < 10; i++) {
ChineseGifCaptcha chineseGifCaptcha = new ChineseGifCaptcha(); ChineseGifCaptcha chineseGifCaptcha = new ChineseGifCaptcha();
System.out.println(chineseGifCaptcha.text()); 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 @Test
public void test2() throws Exception { public void testArit() throws Exception {
String[] colors = new String[]{"#8cc540", "#009f5d", "#019fa0", "#019fde", "#007cdc", "#887ddd", "#cd7bdd", "#ff5675", "#ff1244", "#ff8345", "#f8bd0b", "#d1d2d4"}; /*for (int i = 0; i < 10; i++) {
String[] fonts = new String[]{"actionj.ttf", "epilog.ttf", "fresnel.ttf", "headache.ttf", "lexo.ttf", "prefix.ttf", "progbot.ttf", "ransom.ttf", "robot.ttf", "scandal.ttf"}; ArithmeticCaptcha specCaptcha = new ArithmeticCaptcha();
int i = 0; specCaptcha.setLen(3);
for (String f : fonts) { specCaptcha.setFont(i, 28f);
i++; System.out.println(specCaptcha.getArithmeticString() + " " + specCaptcha.text());
FileOutputStream out = new FileOutputStream(new File("D:/Java/aa" + i + ".png")); specCaptcha.out(new FileOutputStream(new File("C:/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();
}
}
}
} }
@Test @Test
public void test3() throws Exception { public void testBase64() throws Exception {
String filePath = getClass().getResource("/actionj.ttf").getFile(); /*GifCaptcha specCaptcha = new GifCaptcha();
System.out.println(filePath); System.out.println(specCaptcha.toBase64(""));*/
} }
} }

Loading…
Cancel
Save