CaptchaUtilsEx.java 6.6 KB
Newer Older
苗卫卫 committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
package com.starcharge.base.util;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.Arrays;
import java.util.Random;

/**
 * 图片验证码工具类
 */
public class CaptchaUtilsEx {
    
    // 使用到Algerian字体,系统里没有的话需要安装字体,字体只显示大写,去掉了1,0,i,o几个容易混淆的字符
    public static final String VERIFY_CODES = "23456789ABCDEFGHJKLMNPQRSTUVWXYZ";

    public static final String VERIFY_CODES_NUMBER = "0123456789";
    
    private static Random random = new Random();
    
    private BufferedImage image;

	private String imageCode;
	
	public BufferedImage getImage() {
		return image;
	}

	public String getImageCode() {
		return imageCode;
	}
	
	public CaptchaUtilsEx(Integer width, Integer height, Integer verifySize) {
		this.imageCode = generateVerifyCode(verifySize, false);
		this.image = getImage(width, height, verifySize, this.imageCode);
	}

    public CaptchaUtilsEx(Integer width, Integer height, Integer verifySize, boolean onlyNumber) {
        this.imageCode = generateVerifyCode(verifySize, onlyNumber);
        this.image = getImage(width, height, verifySize, this.imageCode);
    }
    
    public static String generateVerifyCode(int verifySize, boolean onlyNumber) {
	    String verifyCodeLib = onlyNumber ? VERIFY_CODES_NUMBER : VERIFY_CODES;
        int codesLen = verifyCodeLib.length();
        Random rand = new Random(System.currentTimeMillis());
        StringBuilder verifyCode = new StringBuilder(verifySize);
        for (int i = 0; i < verifySize; i++) {
            verifyCode.append(verifyCodeLib.charAt(rand.nextInt(codesLen - 1)));
        }
        return verifyCode.toString();
    }
    
    private static Color getRandColor(int fc, int bc) {
        if (fc > 255)
            fc = 255;
        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);
    }
    
    private static int[] getRandomRgb() {
        int[] rgb = new int[3];
        for (int i = 0; i < 3; i++) {
            rgb[i] = random.nextInt(255);
        }
        return 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 void shear(Graphics g, int w1, int h1, Color color) {
        shearX(g, w1, h1, color);
        shearY(g, w1, h1, color);
    }
    
    private static void shearX(Graphics g, int w1, int h1, Color color) {
        
        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) {
        
        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);
            }
            
        }
        
    }
    
    public static BufferedImage getImage(int w, int h, Integer verifySize, String code) {
        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Random rand = new Random();
        Graphics2D g2 = image.createGraphics();
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        Color[] colors = new Color[5];
        Color[] colorSpaces =
            new Color[]{Color.WHITE, Color.CYAN, Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA, Color.ORANGE, Color.PINK, Color.YELLOW};
        float[] fractions = new float[colors.length];
        for (int i = 0; i < colors.length; i++) {
            colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];
            fractions[i] = rand.nextFloat();
        }
        Arrays.sort(fractions);
        
        g2.setColor(Color.GRAY);// 设置边框色
        g2.fillRect(0, 0, w, h);
        
        Color c = getRandColor(200, 250);
        g2.setColor(c);// 设置背景色
        g2.fillRect(0, 2, w, h - 4);
        
        // 绘制干扰线
        Random random = new Random();
        g2.setColor(getRandColor(160, 200));// 设置线条的颜色
        for (int i = 0; i < 20; i++) {
            int x = random.nextInt(w - 1);
            int y = random.nextInt(h - 1);
            int xl = random.nextInt(6) + 1;
            int yl = random.nextInt(12) + 1;
            g2.drawLine(x, y, x + xl + 40, y + yl + 20);
        }
        
        // 添加噪点
        float yawpRate = 0.05f;// 噪声率
        int area = (int)(yawpRate * w * h);
        for (int i = 0; i < area; i++) {
            int x = random.nextInt(w);
            int y = random.nextInt(h);
            int rgb = getRandomIntColor();
            image.setRGB(x, y, rgb);
        }
        
        shear(g2, w, h, c);// 使图片扭曲
        
        g2.setColor(getRandColor(100, 160));
        int fontSize = h - 4;
        //设置验证码字体, 如"Algerian"
        Font font = new Font(null, Font.ITALIC, fontSize);
        g2.setFont(font);
        char[] chars = code.toCharArray();
        for (int i = 0; i < verifySize; i++) {
            AffineTransform affine = new AffineTransform();
            affine.setToRotation(Math.PI / 6 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1), (w / verifySize) * i + fontSize / 2,
                h / 2);
            g2.setTransform(affine);
//            g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10);
            g2.drawChars(chars, i, 1, (w / verifySize) * i , h / 2 + fontSize / 2 - 5);
        }
        
        g2.dispose();
        return image;
    }
}