JAVA生成图片验证码的简单代码实现(干扰线、字扭转、ocr识别)
还记的刚工作的时候,看到网上很多的网站都有图形验证码,感觉很是高级啊。所以就想到在公司内部使用的系统里添加这样一个功能。做完以后,看到登录界面出现了一个验证码图片,又是扭曲,又有干扰线,又有字母|数字|汉字混排,感觉很是高大上啊。满满的成就感。
没想到第二天就被老板批了,你在公司内部使用的系统上做验证码功能是闲的蛋疼么!把自己人都防住了,这系统还能用么。
所以,技术的使用还是要看它的使用环境,要出现在正确的地方。否则会适得其反。
1. 获取并下载图形验证码图片
package com.chl.yzm;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
/**
* 图形验证码的生成
*
* @author chenhailong 可以使用工具 jar:https://mvnrepository.com/search?q=captcha
* 示例:jcaptcha , 官网:http://jcaptcha.sourceforge.net/
*
*/
public class YzmaPicuture {
public static void main(String[] args) {
try {
PictureMaker pm = new PictureMaker();
BufferedImage image = new BufferedImage(pm.getWidth(), pm.getHeight(), BufferedImage.TYPE_INT_BGR);
Graphics2D g = image.createGraphics();
// 定义字体样式
Font myFont = new Font("黑体", Font.BOLD, 50);
// 设置字体
g.setFont(myFont);
g.setColor(pm.getRandomColor(200, 250));
// 绘制背景
g.fillRect(0, 0, pm.getWidth(), pm.getHeight());
g.setColor(pm.getRandomColor(180, 200));
pm.drawRandomLines(g, 20);
//先出现,再画线
String verifyCode = pm.drawRandomString(4, g);
System.out.println("verifyCode:" + verifyCode);
g.dispose();
String path = "/Users/chenhailong/Desktop/test.jpeg";
File f = new File(path);
ImageIO.write(image, "JPEG", f);
// Tess4jOcrTest.test1(path); //识别效果不准
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. 图片生成工具类
package com.chl.yzm;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.util.Random;
/**
* 按照规则生成图片
*
* @author chenhailong 参考 :https://www.iteye.com/blog/1017401036-2315074
*/
public class PictureMaker {
/**
* 验证码图片的宽度。
*/
private int width = 200;
/**
* 验证码图片的高度。
*/
private int height = 100;
/**
* 验证码的数量。
*/
private Random random = new Random();
public PictureMaker() {
}
/**
* 生成随机颜色
*
* @param fc
* 前景色
* @param bc
* 背景色
* @return Color对象,此Color对象是RGB形式的。
*/
public Color getRandomColor(int fc, int bc) {
if (fc > 255)
fc = 200;
if (bc > 255)
bc = 255;
int r = fc + random.nextInt(bc - fc);
int g = fc + random.nextInt(bc - fc);
int b = fc + random.nextInt(bc - fc);
return new Color(r, g, b);
}
/**
* 绘制干扰线
*
* @param g
* Graphics2D对象,用来绘制图像
* @param nums
* 干扰线的条数
*/
public void drawRandomLines(Graphics2D g, int nums) {
g.setColor(this.getRandomColor(160, 200));
for (int i = 0; i < nums; i++) {
int x1 = random.nextInt(width);
int y1 = random.nextInt(height);
int x2 = random.nextInt(12);
int y2 = random.nextInt(12);
g.drawLine(x1, y1, x2, y2);
}
}
/**
* 获取随机字符串, 此函数可以产生由大小写字母,汉字,数字组成的字符串
*
* @param length
* 随机字符串的长度
* @return 随机字符串
*/
public String drawRandomString(int length, Graphics2D g) {
StringBuffer strbuf = new StringBuffer();
String temp = "";
int itmp = 0;
for (int i = 0; i < length; i++) {
switch (random.nextInt(5)) {
case 1: // 生成A~Z的字母
itmp = random.nextInt(26) + 65;
temp = String.valueOf((char) itmp);
break;
case 2: // 生成数字
itmp = random.nextInt(26) + 97;
temp = String.valueOf((char) itmp);
case 3: // 生成汉字\需要处理字符乱码问题
String[] rBase = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f" };
int r1 = random.nextInt(3) + 11; // 生成第1位的区码
String strR1 = rBase[r1]; // 生成11~14的随机数
int r2; // 生成第2位的区码
if (r1 == 13)
r2 = random.nextInt(7); // 生成0~7的随机数
else
r2 = random.nextInt(16); // 生成0~16的随机数
String strR2 = rBase[r2];
int r3 = random.nextInt(6) + 10; // 生成第1位的位码
String strR3 = rBase[r3];
int r4; // 生成第2位的位码
if (r3 == 10)
r4 = random.nextInt(15) + 1; // 生成1~16的随机数
else if (r3 == 15)
r4 = random.nextInt(15); // 生成0~15的随机数
else
r4 = random.nextInt(16); // 生成0~16的随机数
String strR4 = rBase[r4];
// 将生成的机内码转换成数字
byte[] bytes = new byte[2];
String strR12 = strR1 + strR2; // 将生成的区码保存到字节数组的第1个元素中
int tempLow = Integer.parseInt(strR12, 16);
bytes[0] = (byte) tempLow;
String strR34 = strR3 + strR4; // 将生成的区码保存到字节数组的第2个元素中
int tempHigh = Integer.parseInt(strR34, 16);
bytes[1] = (byte) tempHigh;
temp = new String(bytes); // 根据字节数组生成汉字
System.out.println(bytes);
break;
default:
itmp = random.nextInt(10) + 48;
temp = String.valueOf((char) itmp);
break;
}
Color color = new Color(20 + random.nextInt(20), 20 + random.nextInt(20), 20 + random.nextInt(20));
g.setColor(color);
// 想文字旋转一定的角度
AffineTransform trans = new AffineTransform();
trans.rotate(random.nextInt(45) * 3.14 / 180, 15 * i + 8, 7);
// 缩放文字
float scaleSize = random.nextFloat() + 0.8f;
if (scaleSize > 1f)
scaleSize = 1f;
trans.scale(scaleSize, scaleSize);
g.setTransform(trans);
g.drawString(temp, 25 * i + 18, 40);// 字体出现的坐标
strbuf.append(temp);
}
g.dispose();
return strbuf.toString();
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeight() {
return height;
}
public void setHeight(int height) {
this.height = height;
}
}
关于OCR识别,可以参考之前整理的文章,这个效果不太好。可以自己训练或百度找一些收费的机构进行破解。
MAC系统中的JAVA中使用tess4j-4.4.1实现OCR识别的环境搭建(含tesseract安装配置)
原创文章,转载请标明本文链接: JAVA生成图片验证码的简单代码实现(干扰线、字扭转、ocr识别)