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

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

@ -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://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;
![验证码](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;
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftpd0tj6nhj303m01ct8m.jpg)
![验证码](https://s2.ax1x.com/2019/08/23/msknIS.png)
&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;
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovojp2gng303m01cq2w.jpg)
![验证码](https://s2.ax1x.com/2019/08/23/msk6Z6.png)
&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;
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovmy720dj303m01cq2s.jpg)
![验证码](https://s2.ax1x.com/2019/08/23/msAAW4.png)
&emsp;&emsp;
![验证码](https://ws1.sinaimg.cn/large/006a7GCKly1ftovn68um6j303m01cglf.jpg)
![验证码](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
<project>
@ -77,33 +83,49 @@ dependencies {
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>EasyCaptcha</artifactId>
<version>1.5.0</version>
<version>1.6.0</version>
</dependency>
</dependencies>
</project>
```
### 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添加如下
```
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>EasyCaptcha</artifactId>
<version>1.5.0</version>
<systemPath>${basedir}/libs/EasyCaptcha-1.5.0.jar</systemPath>
<version>1.6.0</version>
<systemPath>${basedir}/libs/EasyCaptcha-1.6.0.jar</systemPath>
</dependency>
```
---
## 4.使用方法
## 3.使用方法
### 4.1.在SpringMVC中使用
```java
@Controller
public class CaptchaController {
### 3.1.快速使用
1.在web.xml里面加入如下配置
@RequestMapping("/captcha")
public void captcha(HttpServletRequest request, HttpServletResponse response) throws Exception {
CaptchaUtil.out(request, response);
}
}
```
前端html代码
```html
<img src="/captcha" width="130px" height="48px" />
```
> 不要忘了把`/captcha`路径排除登录拦截比如shiro的拦截。
### 4.2.在servlet中使用
web.xml中配置servlet
```xml
<web-app>
<!-- 图形验证码servlet -->
@ -113,163 +135,130 @@ maven导入jar包在项目根目录创建`libs`文件夹然后pom.xml添
</servlet>
<servlet-mapping>
<servlet-name>CaptchaServlet</servlet-name>
   <url-pattern>/images/captcha</url-pattern>
   <url-pattern>/captcha</url-pattern>
</servlet-mapping>
</web-app>
```
2.前端代码
```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
@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.不使用工具类
&emsp;&emsp;CaptchaUtil是为了简化操作封装了生成验证码、存session、判断验证码等功能。CaptchaUtil使用的GifCaptcha
生成的字母数字混合的gif验证码如果需要设置更多的参数请参照如下操作使用
### 4.5.不使用工具类
&emsp;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验证码
```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);
}
}
```
> 注意:<br/>
> &emsp;算术验证码的len表示是几位数运算而其他验证码的len表示验证码的位数算术验证码的text()表示的是公式的结果,
> 对于算术验证码你应该把公式的结果存储session而不是公式。
### 4.3.验证码类型
### 5.2.验证码字符类型
类型 | 描述
:--- | :---
@ -280,60 +269,145 @@ public class Test {
TYPE_ONLY_LOWER | 纯小写字母
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));
```
// 设置字体
chineseCaptcha.setFont(new Font("楷体", Font.PLAIN, 28)); // 有默认字体,可以不用设置
### 5.4.输出base64编码
```
SpecCaptcha specCaptcha = new SpecCaptcha(130, 48, 5);
specCaptcha.toBase64();
// 生成的验证码
String code = chineseCaptcha.text();
// 如果不想要base64的头部data:image/png;base64,
specCaptcha.toBase64(""); // 加一个空的参数即可
```
// 输出图片流
chineseCaptcha.out(outputStream);
### 5.5.输出到文件
```
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) {
OutputStream outputStream = new FileOutputStream(new File("D:/a/aa.png"));
## 7.自定义效果
// 三个参数分别为宽、高、位数
ChineseGifCaptcha chineseGifCaptcha = new ChineseGifCaptcha(130, 48, 4);
&emsp;继承`Captcha`实现`out`方法,中文验证码可继承`ChineseCaptchaAbstract`,算术验证码可继承`ArithmeticCaptchaAbstract`。
// 设置字体
chineseGifCaptcha.setFont(new Font("楷体", Font.PLAIN, 28)); // 有默认字体,可以不用设置
---
// 生成的验证码
String code = chineseGifCaptcha.text();
## 8.更新日志
// 输出图片流
chineseGifCaptcha.out(outputStream);
}
}
```
- **2019-08-23 (v1.6.0)**
- 增加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>
<artifactId>easy-captcha</artifactId>
<version>1.5.0-RELEASE</version>
<version>1.6.0-RELEASE</version>
<packaging>jar</packaging>
<name>EasyCaptcha</name>
@ -23,7 +23,7 @@
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<version>4.12</version>
<scope>test</scope>
</dependency>
</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
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;
}
}

@ -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);
// 画干扰圆圈
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;
for (int i = 0; i < len; i++) {
ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));
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);
// 计算坐标
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;
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);
}
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();
return image;
}

@ -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];
for (int i = 0; i < len; i++) {
fontcolor[i] = new Color(20 + num(110), 20 + num(110), 20 + num(110));
}
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();
@ -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;

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

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

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

@ -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,9 +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);
out(DEFAULT_WIDTH, DEFAULT_HEIGHT, len, font, request, response);
}
/**
@ -147,57 +92,49 @@ public class CaptchaUtil {
* @param width
* @param height
* @param len
* @param font
* @param request HttpServletRequest
* @param response HttpServletResponse
* @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 {
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 height
* @param len
* @param font
* @param captcha Captcha
* @param request HttpServletRequest
* @param response HttpServletResponse
* @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 {
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 height
* @param len
* @param font
* @param cType
* @param code
* @param request HttpServletRequest
* @param response HttpServletResponse
* @throws IOException IO
* @return
*/
private static void outCaptcha(int width, int height, int len, Font font, int cType, 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);
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);
}
request.getSession().setAttribute(SESSION_KEY, captcha.text().toLowerCase());
captcha.out(response.getOutputStream());
return false;
}
/**

@ -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(""));*/
}
}

Loading…
Cancel
Save