JAVA生成图片验证码的简单代码实现(干扰线、字扭转、ocr识别)

作者: admin 分类: Scrapy 发布时间: 2020-05-09 18:13  阅读: 113 views

还记的刚工作的时候,看到网上很多的网站都有图形验证码,感觉很是高级啊。所以就想到在公司内部使用的系统里添加这样一个功能。做完以后,看到登录界面出现了一个验证码图片,又是扭曲,又有干扰线,又有字母|数字|汉字混排,感觉很是高大上啊。满满的成就感。

没想到第二天就被老板批了,你在公司内部使用的系统上做验证码功能是闲的蛋疼么!把自己人都防住了,这系统还能用么。

所以,技术的使用还是要看它的使用环境,要出现在正确的地方。否则会适得其反。

图形验证码

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识别)

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表评论

电子邮件地址不会被公开。 必填项已用*标注

更多阅读