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

This commit is contained in:
whvcse@foxmail.com
2019-08-23 23:50:26 +08:00
parent 366f54ea80
commit 8ebe5918c9
12 changed files with 640 additions and 527 deletions

View File

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

View File

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

View File

@@ -4,6 +4,7 @@ import com.wf.captcha.base.ChineseCaptchaAbstract;
import com.wf.captcha.utils.GifEncoder;
import java.awt.*;
import java.awt.geom.CubicCurve2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
@@ -30,24 +31,39 @@ public class ChineseGifCaptcha extends ChineseCaptchaAbstract {
@Override
public boolean out(OutputStream os) {
checkAlpha();
boolean ok;
try {
char[] rands = textChar(); // 获取验证码数组
char[] strs = textChar(); // 获取验证码数组
// 随机生成每个文字的颜色
Color fontColor[] = new Color[len];
for (int i = 0; i < len; i++) {
fontColor[i] = color();
}
// 随机生成贝塞尔曲线参数
int x1 = 5, y1 = num(5, height / 2);
int x2 = width - 5, y2 = num(height / 2, height - 5);
int ctrlx = num(width / 4, width / 4 * 3), ctrly = num(5, height - 5);
if (num(2) == 0) {
int ty = y1;
y1 = y2;
y2 = ty;
}
int ctrlx1 = num(width / 4, width / 4 * 3), ctrly1 = num(5, height - 5);
int[][] besselXY = new int[][]{{x1, y1}, {ctrlx, ctrly}, {ctrlx1, ctrly1}, {x2, y2}};
// 开始画gif每一帧
GifEncoder gifEncoder = new GifEncoder();
gifEncoder.start(os);
gifEncoder.setQuality(180);
gifEncoder.setDelay(100);
gifEncoder.setRepeat(0);
BufferedImage frame;
Color fontcolor = color();
gifEncoder.start(os);
for (int i = 0; i < len; i++) {
frame = graphicsImage(fontcolor, rands, i);
BufferedImage frame = graphicsImage(fontColor, strs, i, besselXY);
gifEncoder.addFrame(frame);
frame.flush();
}
gifEncoder.finish();
ok = true;
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
os.close();
@@ -55,60 +71,53 @@ public class ChineseGifCaptcha extends ChineseCaptchaAbstract {
e.printStackTrace();
}
}
return ok;
return false;
}
@Override
public String toBase64() {
return toBase64("data:image/gif;base64,");
}
/**
* 画随机码图
*
* @param fontcolor 随机字体颜色
* @param fontColor 随机字体颜色
* @param strs 字符数组
* @param flag 透明度使用
* @param flag 透明度
* @param besselXY 干扰线参数
* @return BufferedImage
*/
private BufferedImage graphicsImage(Color fontcolor, char[] strs, int flag) {
private BufferedImage graphicsImage(Color[] fontColor, char[] strs, int flag, int[][] besselXY) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) image.getGraphics();
g2d.setColor(Color.WHITE); // 填充背景颜色
// 填充背景颜色
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, width, height);
// 抗锯齿
AlphaComposite ac3;
g2d.setColor(fontcolor);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 画验证码
Font font = getFont();
int hp = (height - font.getSize()) >> 1;
int h = height - hp;
int w = width / strs.length;
int sp = (w - font.getSize()) / 2;
for (int i = 0; i < len; i++) {
ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));
g2d.setComposite(ac3);
// 计算坐标
int x = i * w + sp + num(-3, 3);
int y = h + num(-3, 3);
if (x < 0) {
x = 0;
}
if (x + font.getSize() > width) {
x = width - font.getSize();
}
if (y > height) {
y = height;
}
if (y - font.getSize() < 0) {
y = font.getSize();
}
g2d.setFont(font.deriveFont(num(2) == 0 ? Font.PLAIN : Font.ITALIC));
g2d.drawString(String.valueOf(strs[i]), x, y);
}
// 随机画干扰线
g2d.setStroke(new BasicStroke(1.25f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.45f);
g2d.setComposite(ac3);
drawLine(1, g2d.getColor(), g2d);
// 画干扰圆圈
drawOval(3, g2d.getColor(), g2d);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f * num(10))); // 设置透明度
drawOval(2, g2d);
// 画干扰线
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f)); // 设置透明度
g2d.setStroke(new BasicStroke(1.2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
g2d.setColor(fontColor[0]);
CubicCurve2D shape = new CubicCurve2D.Double(besselXY[0][0], besselXY[0][1], besselXY[1][0], besselXY[1][1], besselXY[2][0], besselXY[2][1], besselXY[3][0], besselXY[3][1]);
g2d.draw(shape);
// 画验证码
g2d.setFont(getFont());
FontMetrics fontMetrics = g2d.getFontMetrics();
int fW = width / strs.length; // 每一个字符所占的宽度
int fSp = (fW - (int) fontMetrics.getStringBounds("W", g2d).getWidth()) / 2; // 字符的左右边距
for (int i = 0; i < strs.length; i++) {
// 设置透明度
AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));
g2d.setComposite(ac3);
g2d.setColor(fontColor[i]);
int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
g2d.drawString(String.valueOf(strs[i]), i * fW + fSp - 3, fY - 3);
}
g2d.dispose();
return image;
}

View File

@@ -4,6 +4,9 @@ import com.wf.captcha.base.Captcha;
import com.wf.captcha.utils.GifEncoder;
import java.awt.*;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.QuadCurve2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.OutputStream;
@@ -34,27 +37,39 @@ public class GifCaptcha extends Captcha {
@Override
public boolean out(OutputStream os) {
checkAlpha();
boolean ok;
try {
char[] rands = textChar(); // 获取验证码数组
char[] strs = textChar(); // 获取验证码数组
// 随机生成每个文字的颜色
Color fontColor[] = new Color[len];
for (int i = 0; i < len; i++) {
fontColor[i] = color();
}
// 随机生成贝塞尔曲线参数
int x1 = 5, y1 = num(5, height / 2);
int x2 = width - 5, y2 = num(height / 2, height - 5);
int ctrlx = num(width / 4, width / 4 * 3), ctrly = num(5, height - 5);
if (num(2) == 0) {
int ty = y1;
y1 = y2;
y2 = ty;
}
int ctrlx1 = num(width / 4, width / 4 * 3), ctrly1 = num(5, height - 5);
int[][] besselXY = new int[][]{{x1, y1}, {ctrlx, ctrly}, {ctrlx1, ctrly1}, {x2, y2}};
// 开始画gif每一帧
GifEncoder gifEncoder = new GifEncoder();
gifEncoder.start(os);
gifEncoder.setQuality(180);
gifEncoder.setDelay(100);
gifEncoder.setRepeat(0);
BufferedImage frame;
Color fontcolor[] = new Color[len];
gifEncoder.start(os);
for (int i = 0; i < len; i++) {
fontcolor[i] = new Color(20 + num(110), 20 + num(110), 20 + num(110));
}
for (int i = 0; i < len; i++) {
frame = graphicsImage(fontcolor, rands, i);
BufferedImage frame = graphicsImage(fontColor, strs, i, besselXY);
gifEncoder.addFrame(frame);
frame.flush();
}
gifEncoder.finish();
ok = true;
return true;
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
os.close();
@@ -62,18 +77,24 @@ public class GifCaptcha extends Captcha {
e.printStackTrace();
}
}
return ok;
return false;
}
@Override
public String toBase64() {
return toBase64("data:image/gif;base64,");
}
/**
* 画随机码图
*
* @param fontcolor 随机字体颜色
* @param fontColor 随机字体颜色
* @param strs 字符数组
* @param flag 透明度使用
* @param flag 透明度
* @param besselXY 干扰线参数
* @return BufferedImage
*/
private BufferedImage graphicsImage(Color[] fontcolor, char[] strs, int flag) {
private BufferedImage graphicsImage(Color[] fontColor, char[] strs, int flag, int[][] besselXY) {
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) image.getGraphics();
// 填充背景颜色
@@ -81,39 +102,27 @@ public class GifCaptcha extends Captcha {
g2d.fillRect(0, 0, width, height);
// 抗锯齿
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.setStroke(new BasicStroke(1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
// 画干扰圆圈
drawOval(4, g2d);
// 随机画干扰线
drawLine(2, g2d);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.1f * num(10))); // 设置透明度
drawOval(2, g2d);
// 画干扰线
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.7f)); // 设置透明度
g2d.setStroke(new BasicStroke(1.2f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
g2d.setColor(fontColor[0]);
CubicCurve2D shape = new CubicCurve2D.Double(besselXY[0][0], besselXY[0][1], besselXY[1][0], besselXY[1][1], besselXY[2][0], besselXY[2][1], besselXY[3][0], besselXY[3][1]);
g2d.draw(shape);
// 画验证码
Font font = getFont();
int hp = (height - font.getSize()) >> 1;
int h = height - hp;
int w = width / strs.length;
int sp = (w - font.getSize()) / 2;
g2d.setFont(getFont());
FontMetrics fontMetrics = g2d.getFontMetrics();
int fW = width / strs.length; // 每一个字符所占的宽度
int fSp = (fW - (int) fontMetrics.getStringBounds("W", g2d).getWidth()) / 2; // 字符的左右边距
for (int i = 0; i < strs.length; i++) {
// 设置透明度
AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, getAlpha(flag, i));
g2d.setComposite(ac3);
g2d.setColor(fontcolor[i]);
// 计算坐标
int x = i * w + sp + num(3);
int y = h - num(3, 6);
// 调整溢出的字
if (x < 8) {
x = 8;
}
if (x + font.getSize() > width) {
x = width - font.getSize();
}
if (y > height) {
y = height;
}
if (y - font.getSize() < 0) {
y = font.getSize();
}
g2d.setFont(font.deriveFont(num(2) == 0 ? Font.PLAIN : Font.ITALIC));
g2d.drawString(String.valueOf(strs[i]), x, y);
g2d.setColor(fontColor[i]);
int fY = height - ((height - (int) fontMetrics.getStringBounds(String.valueOf(strs[i]), g2d).getHeight()) >> 1); // 文字的纵坐标
g2d.drawString(String.valueOf(strs[i]), i * fW + fSp + 3, fY - 3);
}
g2d.dispose();
return image;

View File

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

View File

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

View File

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

View File

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

View File

@@ -7,7 +7,6 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.wf.captcha.base.Captcha;
import com.wf.captcha.GifCaptcha;
import com.wf.captcha.SpecCaptcha;
/**
@@ -16,21 +15,9 @@ import com.wf.captcha.SpecCaptcha;
*/
public class CaptchaUtil {
private static final String SESSION_KEY = "captcha";
/**
* 验证验证码
*
* @param code 用户输入的验证码
* @param request HttpServletRequest
* @return 是否正确
*/
public static boolean ver(String code, HttpServletRequest request) {
if (code != null && !code.trim().isEmpty()) {
String captcha = (String) request.getSession().getAttribute(SESSION_KEY);
return code.trim().toLowerCase().equals(captcha);
}
return false;
}
private static final int DEFAULT_LEN = 4; // 默认长度
private static final int DEFAULT_WIDTH = 130; // 默认宽度
private static final int DEFAULT_HEIGHT = 48; // 默认高度
/**
* 输出验证码
@@ -41,7 +28,7 @@ public class CaptchaUtil {
*/
public static void out(HttpServletRequest request, HttpServletResponse response)
throws IOException {
out(5, request, response);
out(DEFAULT_LEN, request, response);
}
/**
@@ -54,21 +41,7 @@ public class CaptchaUtil {
*/
public static void out(int len, HttpServletRequest request, HttpServletResponse response)
throws IOException {
out(130, 48, len, request, response);
}
/**
* 输出验证码
*
* @param len 长度
* @param font 字体
* @param request HttpServletRequest
* @param response HttpServletResponse
* @throws IOException IO异常
*/
public static void out(int len, Font font, HttpServletRequest request, HttpServletResponse response)
throws IOException {
out(130, 48, len, font, request, response);
out(DEFAULT_WIDTH, DEFAULT_HEIGHT, len, request, response);
}
/**
@@ -89,42 +62,14 @@ public class CaptchaUtil {
/**
* 输出验证码
*
* @param width 宽度
* @param height 高度
* @param len 长度
* @param font 字体
* @param request HttpServletRequest
* @param response HttpServletResponse
* @throws IOException IO异常
*/
public static void out(int width, int height, int len, Font font, HttpServletRequest request, HttpServletResponse response)
public static void out(Font font, HttpServletRequest request, HttpServletResponse response)
throws IOException {
outCaptcha(width, height, len, font, 1, request, response);
}
/**
* 输出验证码
*
* @param request HttpServletRequest
* @param response HttpServletResponse
* @throws IOException IO异常
*/
public static void outPng(HttpServletRequest request, HttpServletResponse response)
throws IOException {
outPng(5, request, response);
}
/**
* 输出验证码
*
* @param len 长度
* @param request HttpServletRequest
* @param response HttpServletResponse
* @throws IOException IO异常
*/
public static void outPng(int len, HttpServletRequest request, HttpServletResponse response)
throws IOException {
outPng(130, 48, len, request, response);
out(DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_LEN, font, request, response);
}
/**
@@ -136,24 +81,9 @@ public class CaptchaUtil {
* @param response HttpServletResponse
* @throws IOException IO异常
*/
public static void outPng(int len, Font font, HttpServletRequest request, HttpServletResponse response)
public static void out(int len, Font font, HttpServletRequest request, HttpServletResponse response)
throws IOException {
outPng(130, 48, len, font, request, response);
}
/**
* 输出验证码
*
* @param width 宽度
* @param height 高度
* @param len 长度
* @param request HttpServletRequest
* @param response HttpServletResponse
* @throws IOException IO异常
*/
public static void outPng(int width, int height, int len, HttpServletRequest request, HttpServletResponse response)
throws IOException {
outPng(width, height, len, null, request, response);
out(DEFAULT_WIDTH, DEFAULT_HEIGHT, len, font, request, response);
}
/**
@@ -167,39 +97,46 @@ public class CaptchaUtil {
* @param response HttpServletResponse
* @throws IOException IO异常
*/
public static void outPng(int width, int height, int len, Font font, HttpServletRequest request, HttpServletResponse response)
public static void out(int width, int height, int len, Font font, HttpServletRequest request, HttpServletResponse response)
throws IOException {
outCaptcha(width, height, len, font, 0, request, response);
SpecCaptcha specCaptcha = new SpecCaptcha(width, height, len);
if (font != null) {
specCaptcha.setFont(font);
}
out(specCaptcha, request, response);
}
/**
* 输出验证码
*
* @param width 宽度
* @param height 高度
* @param len 长度
* @param font 字体
* @param cType 类型
* @param captcha Captcha
* @param request HttpServletRequest
* @param response HttpServletResponse
* @throws IOException IO异常
*/
private static void outCaptcha(int width, int height, int len, Font font, int cType, HttpServletRequest request, HttpServletResponse response)
private static void out(Captcha captcha, HttpServletRequest request, HttpServletResponse response)
throws IOException {
setHeader(response);
Captcha captcha = null;
if (cType == 0) {
captcha = new SpecCaptcha(width, height, len);
} else if (cType == 1) {
captcha = new GifCaptcha(width, height, len);
}
if (font != null) {
captcha.setFont(font);
}
request.getSession().setAttribute(SESSION_KEY, captcha.text().toLowerCase());
captcha.out(response.getOutputStream());
}
/**
* 验证验证码
*
* @param code 用户输入的验证码
* @param request HttpServletRequest
* @return 是否正确
*/
public static boolean ver(String code, HttpServletRequest request) {
if (code != null) {
String captcha = (String) request.getSession().getAttribute(SESSION_KEY);
return code.trim().toLowerCase().equals(captcha);
}
return false;
}
/**
* 清除session中的验证码
*

View File

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