欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

JAVA中图片验证码的生成

程序员文章站 2022-05-11 23:20:09
...
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.Random;

import javax.imageio.ImageIO;

/**
 * 图片验证码生成工具类
 * 
 * @author tuozixuan
 */
public class ImageCodeHandler
{
    // 图片宽度默认值
    private int imageWidth = 100;

    // 图片高度默认值
    private int imageHeight = 50;

    // 图片验证码长度
    private int codeLength = 4;

    // 噪点率(噪点分布的疏密)
    private float yawpRate = 0.012f;

    // 字体大小
    private int fontSize = 28;

    // 图片是否需要扭曲变形
    private boolean isDistortion = true;
    
    // 图片验证码
    private String imageCode = "";

    // 输出的图片格式
    private static final String imageFormat = "jpg";

    // 0,1,2易和字母的o,l,z易混淆,不生成,可以生成汉字
    private static char[] captchars = new char[] { '2', '3', '4', '5', '6', '7', '8', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'j', 'k', 'm', 'n',
            'p', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U',
            'V', 'W', 'X', 'Y' };

    /**
     * 把生成的验证码图片写到指定目录文件中
     * 
     * @param filePath 目录文件
     * @throws IOException
     */
    public void createImageFile(String filePath) throws IOException
    {
        OutputStream fos = new FileOutputStream(new File(filePath));
        BufferedImage bufferedImage = createImage(getImageWidth(), getImageHeight());
        ImageIO.write(bufferedImage, imageFormat, fos);
    }

    /**
     * 把创建好的图片验证码放入输出流中
     * 
     * @param os 输出流
     * @throws IOException
     */
    public String createImage(OutputStream os) throws IOException
    {
        BufferedImage bufferedImage = createImage(getImageWidth(), getImageHeight());
        ImageIO.write(bufferedImage, imageFormat, os);
        return this.imageCode;
    }

    /**
     * 创建指定宽高的验证码图片对象
     * 
     * @param imageWidth 图片宽度
     * @param imageHeight 图片高度
     * @return BufferedImage 图片对象
     */
    public BufferedImage createImage(int imageWidth, int imageHeight)
    {
        // 创建一个指定宽高并带索引的字节图像对象
        BufferedImage bufferedImage = new BufferedImage(imageWidth, imageHeight, BufferedImage.TYPE_BYTE_INDEXED);

        // 创建一个二维图形对象以进行更复杂的图像绘制
        Graphics2D graphics2D = bufferedImage.createGraphics();

        // 设置背景色
        Color color = getRandomColor(200, 250);
        graphics2D.setColor(color);

        // 填充指定宽高的矩形,其中x,y坐标为0
        graphics2D.fillRect(0, 0, bufferedImage.getWidth(), bufferedImage.getHeight());

        // 加字符
        graphics2D.setColor(getRandomColor());
        drawString(graphics2D, getCodeLength());
        //drawCnString(graphics2D, getCodeLength());

        // 加一道线
        drawThickLine(graphics2D, 0, imageWidth / (2) + 1, imageWidth, imageHeight / (3) + 1, 4, getRandomColor(100, 200));

        // 加干扰短线
        setLTAttachLine(graphics2D, imageWidth, imageHeight);
        setRBAttachLine(graphics2D, imageWidth, imageHeight);

        // 使图片扭曲
        if (isDistortion)
        {
            shear(graphics2D, bufferedImage.getWidth(), bufferedImage.getHeight(), color);
        }

        // 设置噪点
        setYawp(bufferedImage, getYawpRate());

        return bufferedImage;
    }

    /**
     * 在图片上画上字符
     * 
     * @param graphics2D 图形对象
     * @param length 字符长度
     */
    private void drawString(Graphics2D graphics2D, int length)
    {
        int car = captchars.length - 1;
        Random random = new Random();

        // 随机写字母或汉字
        String text = "";
        for (int i = 0; i < length; i++)
        {
            // 1.随机得到num个字母或数字
            text += captchars[random.nextInt(car) + 1];
        }
        this.imageCode = text;

        int xOffset = 1 + new Random().nextInt(40);
        int yOffset = 30;

        char[] charArray = text.toCharArray();
        for (int i = 0; i < charArray.length; i++)
        {
            graphics2D.setFont(getRandomFont());
            graphics2D.drawString(String.valueOf(charArray[i]), xOffset, yOffset);
            xOffset = xOffset + 14 + new Random().nextInt(5);
        }
    }

    private void drawCnString(Graphics2D graphics2D, int length)
    {

        int xOffset = 1 + new Random().nextInt(40);
        int yOffset = 30;
        for (int i = 0; i < length; i++)
        {
            graphics2D.setFont(getRandomCnFont());
            graphics2D.drawString(String.valueOf(getRandomCnChar()), xOffset, yOffset);
            xOffset = xOffset + 20 + new Random().nextInt(5);
        }
    }

    /**
     * 从左上到右下加上多道干扰线
     */
    private static void setLTAttachLine(Graphics2D graphics2D, int imageWidth, int imageHeight)
    {
        int lineLeft = 7;// 从左上到右下的线条个数
        Random random = new Random();
        for (int i = 0; i < lineLeft; i++)
        {
            int x = random.nextInt(imageWidth - 1);
            int y = random.nextInt(imageHeight - 1);
            int xl = random.nextInt(6) + 1;
            int yl = random.nextInt(12) + 1;
            graphics2D.drawLine(x, y, x + xl + 40, y + yl + 20);
        }
    }

    /**
     * 从右上到左下加多道干扰线
     */
    private static void setRBAttachLine(Graphics2D graphics2D, int imageWidth, int imageHeight)
    {

        int lineRight = 8;// 从右上到左下的线条个数
        Random random = new Random();
        for (int i = 0; i < lineRight; i++)
        {
            int x = random.nextInt(imageWidth - 1);
            int y = random.nextInt(imageHeight - 1);
            int xl = random.nextInt(12) + 1;
            int yl = random.nextInt(6) + 1;
            graphics2D.drawLine(x, y, x - xl + 40, y - yl);
        }
    }

    /**
     * 设置噪点
     * 
     * @param bufferedImage 图片对象
     * @param yawpRate 噪声率
     */
    private static void setYawp(BufferedImage bufferedImage, float yawpRate)
    {
        int width = bufferedImage.getWidth();
        int height = bufferedImage.getHeight();

        int area = (int) (yawpRate * width * height);
        Random random = new Random();
        for (int i = 0; i < area; i++)
        {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int rgb = getRandomIntColor();
            bufferedImage.setRGB(x, y, rgb);
        }
    }

    private static int getRandomIntColor()
    {
        int[] rgb = getRandomRgb();
        int color = 0;
        for (int c : rgb)
        {
            color = color << 8;
            color = color | c;
        }
        return color;
    }

    private static int[] getRandomRgb()
    {
        int[] rgb = new int[3];
        Random random = new Random();
        for (int i = 0; i < 3; i++)
        {
            rgb[i] = random.nextInt(255);
        }
        return rgb;
    }

    /**
     * 随机得到一个汉字的方法
     * 
     * @return char
     */
    protected char getRandomCnChar()
    {
        final int minFirstByte = 176;
        final int maxFirstByte = 215;
        final int minSecondByte = 161;
        final int maxSecondByte = 249;

        byte[] b = new byte[2];
        b[0] = (byte) (getRandomIntBetween(minFirstByte, maxFirstByte));
        b[1] = (byte) (getRandomIntBetween(minSecondByte, maxSecondByte));
        try
        {
            String s = new String(b, "gb2312");
            System.out.println(s);
            assert s.length() == 1;
            return s.toCharArray()[0];
        }
        catch (UnsupportedEncodingException uee)
        {
            // 重试
            return getRandomCnChar();
        }
    }

    /**
     * 获取两个整数之间的某个随机数,包含较小的整数,不包含较大的整数
     * 
     * @param first 第一个整数
     * @param second 第二个整数
     * @return
     */
    private static int getRandomIntBetween(int first, int second)
    {
        Random random = new Random();
        if (second < first)
        {
            int tmp = first;
            first = second;
            second = tmp;
        }
        return random.nextInt(second - first) + first;
    }

    /**
     * 产生随机字体
     */
    private Font getRandomFont()
    {
        Random random = new Random();
        Font font[] = new Font[5];
        int fontSize = getFontSize();
        font[0] = new Font("Algerian", Font.PLAIN, fontSize);
        font[1] = new Font("Antique Olive Compact", Font.PLAIN, fontSize);
        font[2] = new Font("Fixedsys", Font.PLAIN, fontSize);
        font[3] = new Font("Algerian", Font.PLAIN, fontSize);
        font[4] = new Font("Arial", Font.PLAIN, fontSize);
        return font[random.nextInt(5)];
    }

    /**
     * 产生随机中文字体
     */
    private Font getRandomCnFont()
    {
        Random random = new Random();
        Font font[] = new Font[5];
        int fontSize = getFontSize();
        font[0] = new Font("微软雅黑", Font.PLAIN, fontSize);
        font[1] = new Font("宋体", Font.PLAIN, fontSize);
        font[2] = new Font("新宋体", Font.PLAIN, fontSize);
        font[3] = new Font("楷体", Font.PLAIN, fontSize);
        font[4] = new Font("幼圆", Font.PLAIN, fontSize);
        return font[random.nextInt(5)];
    }

    /**
     * 给定范围获得随机颜色
     * 
     * @param fc 颜色范围-小
     * @param bc 颜色范围-大
     * @return Color 随机颜色
     */
    private static Color getRandomColor(int fc, int bc)
    {
        if (fc > 255)
        {
            fc = 255;
        }
        if (bc > 255)
        {
            bc = 255;
        }
        Random random = new Random();
        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);
    }

    private static Color getRandomColor()
    {
        Random random = new Random();
        Color color[] = new Color[10];
        color[0] = new Color(32, 158, 25);
        color[1] = new Color(218, 42, 19);
        color[2] = new Color(31, 75, 208);
        return color[random.nextInt(3)];
    }

    // 画一道粗线的方法
    private static void drawThickLine(Graphics g, int x1, int y1, int x2, int y2, int thickness, Color c)
    {

        // The thick line is in fact a filled polygon
        g.setColor(c);
        int dX = x2 - x1;
        int dY = y2 - y1;
        // line length
        double lineLength = Math.sqrt(dX * dX + dY * dY);

        double scale = (double) (thickness) / (2 * lineLength);

        // The x and y increments from an endpoint needed to create a
        // rectangle...
        double ddx = -scale * (double) dY;
        double ddy = scale * (double) dX;
        ddx += (ddx > 0) ? 0.5 : -0.5;
        ddy += (ddy > 0) ? 0.5 : -0.5;
        int dx = (int) ddx;
        int dy = (int) ddy;

        // Now we can compute the corner points...
        int xPoints[] = new int[4];
        int yPoints[] = new int[4];

        xPoints[0] = x1 + dx;
        yPoints[0] = y1 + dy;
        xPoints[1] = x1 - dx;
        yPoints[1] = y1 - dy;
        xPoints[2] = x2 - dx;
        yPoints[2] = y2 - dy;
        xPoints[3] = x2 + dx;
        yPoints[3] = y2 + dy;

        g.fillPolygon(xPoints, yPoints, 4);
    }

    private static void shearX(Graphics g, int w1, int h1, Color color)
    {

        Random random = new Random();
        int period = random.nextInt(2);

        boolean borderGap = true;
        int frames = 1;
        int phase = random.nextInt(2);

        for (int i = 0; i < h1; i++)
        {
            double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
            g.copyArea(0, i, w1, 1, (int) d, 0);
            if (borderGap)
            {
                g.setColor(color);
                g.drawLine((int) d, i, 0, i);
                g.drawLine((int) d + w1, i, w1, i);
            }
        }

    }

    private static void shearY(Graphics g, int w1, int h1, Color color)
    {

        Random random = new Random();
        int period = random.nextInt(40) + 10; // 50;

        boolean borderGap = true;
        int frames = 20;
        int phase = 7;
        for (int i = 0; i < w1; i++)
        {
            double d = (double) (period >> 1) * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
            g.copyArea(i, 0, 1, h1, 0, (int) d);
            if (borderGap)
            {
                g.setColor(color);
                g.drawLine(i, (int) d, i, 0);
                g.drawLine(i, (int) d + h1, i, h1);
            }

        }

    }

    /**
     * 使图片扭曲
     * 
     * @param graphics 图形对象
     * @param width 宽度
     * @param height 高度
     * @param color 颜色对象
     */
    private static void shear(Graphics graphics, int width, int height, Color color)
    {
        shearX(graphics, width, height, color);
        shearY(graphics, width, height, color);
    }

    public int getImageWidth()
    {
        return imageWidth;
    }

    public void setImageWidth(int imageWidth)
    {
        if (imageWidth > 0)
        {
            this.imageWidth = imageWidth;
        }
    }

    public int getImageHeight()
    {
        return imageHeight;
    }

    public void setImageHeight(int imageHeight)
    {
        if (imageHeight > 0)
        {
            this.imageHeight = imageHeight;
        }
    }

    public int getCodeLength()
    {
        return codeLength;
    }

    public void setCodeLength(int codeLength)
    {
        if (codeLength > 0)
        {
            this.codeLength = codeLength;
        }
    }

    public float getYawpRate()
    {
        return yawpRate;
    }

    public void setYawpRate(float yawpRate)
    {
        this.yawpRate = yawpRate;
    }

    public int getFontSize()
    {
        return fontSize;
    }

    public void setFontSize(int fontSize)
    {
        this.fontSize = fontSize;
    }

    public boolean isDistortion()
    {
        return isDistortion;
    }

    public void setDistortion(boolean isDistortion)
    {
        this.isDistortion = isDistortion;
    }
}

 

使用示例:

 

import com.cogcn.framework.util.ImageCodeHandler;

public class Test
{

    public static void main(String[] args) throws Exception
    {
        ImageCodeHandler handler = new ImageCodeHandler();
        handler.setCodeLength(4);
        handler.setImageWidth(100);
        handler.setImageHeight(50);
        handler.setYawpRate(0.2f);
        handler.setFontSize(18);
        handler.createImageFile("D:\\imageCode.jpg");
    }
}