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

增加内置字体,增加贝赛尔曲线干扰线

This commit is contained in:
whvcse@foxmail.com 2019-08-22 17:14:16 +08:00
parent b390fe3f3f
commit 366f54ea80
22 changed files with 194 additions and 44 deletions

View File

@ -1,5 +1,7 @@
package com.wf.captcha; package com.wf.captcha;
import com.wf.captcha.base.ChineseCaptchaAbstract;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
@ -58,6 +60,7 @@ public class ChineseCaptcha extends ChineseCaptchaAbstract {
g.fillRect(0, 0, width, height); g.fillRect(0, 0, width, height);
// 抗锯齿 // 抗锯齿
g.setColor(color()); g.setColor(color());
Font font = getFont();
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int hp = (height - font.getSize()) >> 1; int hp = (height - font.getSize()) >> 1;
int h = height - hp; int h = height - hp;

View File

@ -1,5 +1,8 @@
package com.wf.captcha; package com.wf.captcha;
import com.wf.captcha.base.ChineseCaptchaAbstract;
import com.wf.captcha.utils.GifEncoder;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
@ -73,6 +76,7 @@ public class ChineseGifCaptcha extends ChineseCaptchaAbstract {
g2d.setColor(fontcolor); g2d.setColor(fontcolor);
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
// 画验证码 // 画验证码
Font font = getFont();
int hp = (height - font.getSize()) >> 1; int hp = (height - font.getSize()) >> 1;
int h = height - hp; int h = height - hp;
int w = width / strs.length; int w = width / strs.length;

View File

@ -1,5 +1,8 @@
package com.wf.captcha; package com.wf.captcha;
import com.wf.captcha.base.Captcha;
import com.wf.captcha.utils.GifEncoder;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
@ -84,6 +87,7 @@ public class GifCaptcha extends Captcha {
// 随机画干扰线 // 随机画干扰线
drawLine(2, g2d); drawLine(2, g2d);
// 画验证码 // 画验证码
Font font = getFont();
int hp = (height - font.getSize()) >> 1; int hp = (height - font.getSize()) >> 1;
int h = height - hp; int h = height - hp;
int w = width / strs.length; int w = width / strs.length;

View File

@ -1,5 +1,7 @@
package com.wf.captcha; package com.wf.captcha;
import com.wf.captcha.base.Captcha;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
import java.io.IOException; import java.io.IOException;
@ -40,7 +42,6 @@ public class SpecCaptcha extends Captcha {
*/ */
@Override @Override
public boolean out(OutputStream out) { public boolean out(OutputStream out) {
checkAlpha();
return graphicsImage(textChar(), out); return graphicsImage(textChar(), out);
} }
@ -52,51 +53,51 @@ public class SpecCaptcha extends Captcha {
* @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 g = (Graphics2D) bi.getGraphics();
// 填充背景
g.setColor(Color.WHITE); g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height); g.fillRect(0, 0, width, height);
// 抗锯齿 // 抗锯齿
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g.setStroke(new BasicStroke(1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); g.setStroke(new BasicStroke(1.3f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
// 随机画干扰线 // 随机画干扰线
drawLine(3, g); // drawLine(3, g);
// 随机画干扰圆 // 随机画干扰圆
drawOval(8, g); // drawOval(8, g);
drawBesselLine(2, g);
// 画字符串 // 画字符串
AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f);// 指定透明度 // AlphaComposite ac3 = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.8f);// 指定透明度
g.setComposite(ac3); // g.setComposite(ac3);
int hp = (height - font.getSize()) >> 1; g.setFont(getFont());
int h = height - hp; int fontSize = getFont().getSize();
int w = width / strs.length; int fY = height - ((height - fontSize) >> 1); // 文字的纵坐标
int sp = (w - font.getSize()) / 2; int fW = width / strs.length; // 每一个字符所占的宽度
int fSp = (fW - fontSize) / 2; // 字符的左右边距
for (int i = 0; i < strs.length; i++) { for (int i = 0; i < strs.length; i++) {
g.setColor(new Color(20 + num(110), 20 + num(110), 20 + num(110))); g.setColor(color());
// 计算坐标 // 计算坐标
int x = i * w + sp + num(3); int x = i * fW + fSp;
int y = h - num(3, 6); int y = fY/* - num(3, 6)*/;
if (x < 8) { /*if (x < 8) {
x = 8; x = 8;
} }
if (x + font.getSize() > width) { if (x + fontSize > width) {
x = width - font.getSize(); x = width - fontSize;
} }*/
if (y > height) { /*if (y > height) {
y = height; y = height;
} }
if (y - font.getSize() < 0) { if (y - fontSize < 0) {
y = font.getSize(); y = fontSize;
} }*/
g.setFont(font.deriveFont(num(2) == 0 ? Font.PLAIN : Font.ITALIC));
g.drawString(String.valueOf(strs[i]), x, y); g.drawString(String.valueOf(strs[i]), x, y);
} }
ImageIO.write(bi, "png", out); ImageIO.write(bi, "png", out);
out.flush(); out.flush();
ok = true; return true;
} catch (IOException e) { } catch (IOException e) {
ok = false;
e.printStackTrace(); e.printStackTrace();
} finally { } finally {
try { try {
@ -105,6 +106,6 @@ public class SpecCaptcha extends Captcha {
e.printStackTrace(); e.printStackTrace();
} }
} }
return ok; return false;
} }
} }

View File

@ -1,6 +1,10 @@
package com.wf.captcha; package com.wf.captcha.base;
import java.awt.*; import java.awt.*;
import java.awt.geom.CubicCurve2D;
import java.awt.geom.QuadCurve2D;
import java.io.File;
import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
/** /**
@ -8,20 +12,33 @@ import java.io.OutputStream;
* Created by 王帆 on 2018-07-27 上午 10:08. * Created by 王帆 on 2018-07-27 上午 10:08.
*/ */
public abstract class Captcha extends Randoms { public abstract class Captcha extends Randoms {
protected Font font = new Font("Arial", Font.BOLD, 32); // 字体Verdana // 常用颜色
protected int len = 4; // 验证码随机字符长度 public static final int[][] COLOR = {{0, 135, 255}, {51, 153, 51}, {255, 102, 102}, {255, 153, 0}, {153, 102, 0}, {153, 102, 153}, {51, 153, 153}, {102, 102, 255}, {0, 102, 204}, {204, 51, 51}, {0, 153, 204}, {0, 51, 102}};
protected int width = 130; // 验证码显示宽度 // 验证码文本类型
protected int height = 48; // 验证码显示高度
protected String chars = null; // 当前验证码
protected int charType = TYPE_DEFAULT; // 验证码类型1字母数字混合2纯数字3纯字母
public static final int TYPE_DEFAULT = 1; // 字母数字混合 public static final int TYPE_DEFAULT = 1; // 字母数字混合
public static final int TYPE_ONLY_NUMBER = 2; // 纯数字 public static final int TYPE_ONLY_NUMBER = 2; // 纯数字
public static final int TYPE_ONLY_CHAR = 3; // 纯字母 public static final int TYPE_ONLY_CHAR = 3; // 纯字母
public static final int TYPE_ONLY_UPPER = 4; // 纯大写字母 public static final int TYPE_ONLY_UPPER = 4; // 纯大写字母
public static final int TYPE_ONLY_LOWER = 5; // 纯小写字母 public static final int TYPE_ONLY_LOWER = 5; // 纯小写字母
public static final int TYPE_NUM_AND_UPPER = 6; // 数字大写字母 public static final int TYPE_NUM_AND_UPPER = 6; // 数字大写字母
// 常用颜色 // 内置字体
public static final int[][] COLOR = {{0, 135, 255}, {51, 153, 51}, {255, 102, 102}, {255, 153, 0}, {153, 102, 0}, {153, 102, 153}, {51, 153, 153}, {102, 102, 255}, {0, 102, 204}, {204, 51, 51}, {0, 153, 204}, {0, 51, 102}}; public static final int FONT_1 = 0;
public static final int FONT_2 = 1;
public static final int FONT_3 = 2;
public static final int FONT_4 = 3;
public static final int FONT_5 = 4;
public static final int FONT_6 = 5;
public static final int FONT_7 = 6;
public static final int FONT_8 = 7;
public static final int FONT_9 = 8;
public static final int FONT_10 = 9;
private static final String[] FONT_NAMES = new String[]{"actionj.ttf", "epilog.ttf", "fresnel.ttf", "headache.ttf", "lexo.ttf", "prefix.ttf", "progbot.ttf", "ransom.ttf", "robot.ttf", "scandal.ttf"};
private Font font = null; // 验证码的字体
protected int len = 5; // 验证码随机字符长度
protected int width = 130; // 验证码显示宽度
protected int height = 48; // 验证码显示高度
protected int charType = TYPE_DEFAULT; // 验证码类型
protected String chars = null; // 当前验证码
/** /**
* 生成随机验证码 * 生成随机验证码
@ -112,7 +129,7 @@ public abstract class Captcha extends Randoms {
} }
/** /**
* 检查验证码是否生成没有立即生成 * 检查验证码是否生成没有立即生成
*/ */
public void checkAlpha() { public void checkAlpha() {
if (chars == null) { if (chars == null) {
@ -175,7 +192,53 @@ public abstract class Captcha extends Randoms {
} }
} }
/**
* 随机画贝塞尔曲线
*
* @param num 数量
* @param g Graphics2D
*/
public void drawBesselLine(int num, Graphics2D g) {
drawBesselLine(num, null, g);
}
/**
* 随机画贝塞尔曲线
*
* @param num 数量
* @param color 颜色
* @param g Graphics2D
*/
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);
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);
CubicCurve2D shape = new CubicCurve2D.Double(x1, y1, ctrlx, ctrly, ctrlx1, ctrly1, x2, y2);
g.draw(shape);
}
}
}
public Font getFont() { public Font getFont() {
if (font == null) {
try {
setFont(FONT_1);
} catch (Exception e) {
setFont(new Font("Arial", Font.BOLD, 32));
}
}
return font; return font;
} }
@ -183,6 +246,14 @@ public abstract class Captcha extends Randoms {
this.font = font; this.font = font;
} }
public void setFont(int font) throws IOException, FontFormatException {
setFont(font, Font.BOLD, 32f);
}
public void setFont(int font, int style, float size) throws IOException, FontFormatException {
this.font = Font.createFont(Font.TRUETYPE_FONT, new File(getClass().getResource("/" + FONT_NAMES[font]).getFile())).deriveFont(style, size);
}
public int getLen() { public int getLen() {
return len; return len;
} }

View File

@ -1,4 +1,6 @@
package com.wf.captcha; package com.wf.captcha.base;
import com.wf.captcha.base.Captcha;
import java.awt.*; import java.awt.*;

View File

@ -1,4 +1,4 @@
package com.wf.captcha; package com.wf.captcha.base;
import java.util.Random; import java.util.Random;

View File

@ -6,7 +6,7 @@ import java.io.IOException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import com.wf.captcha.Captcha; import com.wf.captcha.base.Captcha;
import com.wf.captcha.GifCaptcha; import com.wf.captcha.GifCaptcha;
import com.wf.captcha.SpecCaptcha; import com.wf.captcha.SpecCaptcha;

View File

@ -1,4 +1,4 @@
package com.wf.captcha; package com.wf.captcha.utils;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;

View File

@ -1,4 +1,4 @@
package com.wf.captcha; package com.wf.captcha.utils;
import java.awt.*; import java.awt.*;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;

View File

@ -1,4 +1,4 @@
package com.wf.captcha; package com.wf.captcha.utils;
/** /**
* *

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
src/main/resources/lexo.ttf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,9 +1,15 @@
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;
/** /**
* 测试类 * 测试类
@ -13,12 +19,13 @@ public class CaptchaTest {
@Test @Test
public void test() throws Exception { public void test() throws Exception {
/*for (int i = 0; i < 5; i++) { for (int i = 0; i < 5; i++) {
SpecCaptcha specCaptcha = new SpecCaptcha(); SpecCaptcha specCaptcha = new SpecCaptcha();
specCaptcha.setCharType(Captcha.TYPE_ONLY_UPPER); // specCaptcha.setCharType(Captcha.TYPE_ONLY_UPPER);
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("D:/Java/aa" + i + ".png"))); specCaptcha.out(new FileOutputStream(new File("D:/Java/aa" + i + ".png")));
}*/ }
} }
@Test @Test
@ -48,4 +55,62 @@ public class CaptchaTest {
}*/ }*/
} }
@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();
}
}
}
}
@Test
public void test3() throws Exception {
String filePath = getClass().getResource("/actionj.ttf").getFile();
System.out.println(filePath);
}
} }