一个生成网页验证码的类 (mycome-validate)
一个小练习
可以通过 BufferedImage next() 返回一个内存图片
也可以通过String void next(OutputStream out) 写到一个输出流中,并返回验证码的值
jar包下载:https://files.cnblogs.com/mycome/mycome-validate.zip
package validate; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.image.BufferedImage; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.OutputStream; import javax.imageio.ImageIO; public class Validate { // 支持的验证码干扰效果 public static final int ROTATE = Integer.parseInt("00000001", 2);// 旋转 public static final int CIRCLE = Integer.parseInt("00000010", 2);// 干扰圈 public static final int LINE = Integer.parseInt("00000100", 2);// 干扰线 public static final int FOG = Integer.parseInt("00001000", 2);// 雾化 public static final int LIGHTER = Integer.parseInt("00010000", 2);// 颜色变淡 // 验证码属性 private int width; // 尺寸 private int height; private int size;// 字符数 private int fontSize;// 字体大小 private int interval;// 字符间隔 private int obstruction;// 干扰效果 private String value;// 验证码的字符值 private Graphics2D graphics;// 绘图器 private BufferedImage validate;// 结果对象 private String range;// 取字范围 // 构造方法 public Validate(int width, int height, int size, int obstruction, String rangeSource) { // 初始化验证码的尺寸 this.width = width; this.height = height; // 初始化验证码的字符数 this.size = size; // 设定验证码的干扰效果 this.obstruction = obstruction; // 设定字体大小和间隔 calculateSize(); // 设置验证码范围 setRange(rangeSource); } // 生成验证码 public BufferedImage next() { // 生成图片 validate = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); graphics = (Graphics2D) validate.getGraphics(); addBackground(); // 添加文字 addCharacters(); // 添加干扰 addObstruction(); return validate; } // 把验证码图片当作流输出 public String next(OutputStream out) throws IOException { next(); ImageIO.write(validate, "jpg", out); return value; } // 设置背景色 private void addBackground() { // 设置背景色为淡灰色 graphics.setColor(new Color(0xf8f8f8)); graphics.fillRect(0, 0, width, height); } // 添加文字 private void addCharacters() { // 设置字体 graphics.setFont(new Font("宋体", Font.BOLD, fontSize)); graphics.setColor(Color.black); // 字符位置标记 int x = 0; int y = (height - fontSize) / 2 + fontSize; Character c; // 取字范围 int len = range.length(); // 判断是否需要旋转 boolean doRotate = (obstruction % 2) != 0 ? true : false; double radian = 0; // 画出字体 value = ""; for (int i = 0; i < size; i++) { x += interval; // 设定旋转角度 if (doRotate) radian = Math.random() * Math.PI / 3 - Math.PI / 6; if (doRotate) graphics.rotate(radian, x + fontSize / 2, y - fontSize / 2); // 取字,画字 c = range.charAt((int) (Math.random() * len)); value += c.toString(); graphics.drawString(c.toString(), x, y); // 恢复旋转角度 if (doRotate) graphics.rotate(-radian, x + fontSize / 2, y - fontSize / 2); x += fontSize; } } // 画干扰物 private void addObstruction() { // 定义变量 boolean needCircle = false; boolean needLine = false; boolean needFog = false; boolean needLighter = false; // 为以上变量赋值 if ((obstruction & CIRCLE) == CIRCLE) needCircle = true; if ((obstruction & LINE) == LINE) needLine = true; if ((obstruction & FOG) == FOG) needFog = true; if ((obstruction & LIGHTER) == LIGHTER) needLighter = true; // 添加干扰物 if (needCircle) addCircle(); if (needLine) addLine(); if (needFog) addFog(); if (needLighter) addLighter(); } // 增加验证码图片的亮度 private void addLighter() { for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { // 获得原来的颜色 int color = validate.getRGB(i, j); color += 256 * 256 * 4; color += 256 * 4; color += 4; // 设置更亮的颜色 validate.setRGB(i, j, color); } } } // 添加雾化效果 private void addFog() { // 设置雾化的颜色是灰色 Color pointColor = Color.DARK_GRAY; // 设置雾化的密度是1/4; for (int i = 0; i < width; i += 4) { for (int j = 0; j < height; j += 4) { validate.setRGB(i, j, pointColor.getRGB()); } } } // 添加干扰线 private void addLine() { // 定义干扰线的起点和终点 int startX; int startY; int endX; int endY; // 设置颜色 graphics.setColor(Color.GRAY); // 画干扰线 for (int i = 0; i < 5; i++) { startX = (int) (Math.random() * width); startY = (int) (Math.random() * height); endX = (int) (Math.random() * width); endY = (int) (Math.random() * height); graphics.drawLine(startX, startY, endX, endY); } } // 添加干扰圈 private void addCircle() { int x; int y; int oval; for (int i = 0; i < 5; i++) { x = (int) (Math.random() * width); y = (int) (Math.random() * height); oval = (int) (Math.random() * (height / 2 - 5)); graphics.drawOval(x, y, oval, oval); } } // 设定字体大小和间隔 private void calculateSize() { int interval; int fontSize; // 计算合适的字体尺寸 int accordingToWidth = (width - ((size + 1) * 5)) / size; int accordingToHeight = height - 10; fontSize = accordingToWidth < accordingToHeight ? accordingToWidth : accordingToHeight; // 计算合适的间隔尺寸 interval = (width - (fontSize * size)) / (size + 1); // 初始化成员变量 this.fontSize = fontSize; this.interval = interval; } // 设置验证码的取字范围 private void setRange(String rangeSource) { FileInputStream in = null; byte[] buf = new byte[1024]; int len; // 从文件读取数据 try { in = new FileInputStream(rangeSource); while ((len = in.read(buf, 0, 1024)) > 0) { range += new String(buf, 0, len); } } catch (FileNotFoundException e) { new RuntimeException("读取验证码取字范围失败", e); } catch (IOException e) { new RuntimeException("读取验证码取字范围失败", e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { } } } } }