• 验证码生成工具


    验证码生成工具

      1 /**
      2  * <html>
      3  * <body>
      4  *  <P> Copyright 1994 JsonInternational</p>
      5  *  <p> All rights reserved.</p>
      6  *  <p> Created on 19941115</p>
      7  *  <p> Created by Jason</p>
      8  *  </body>
      9  * </html>
     10  */
     11 package cn.ucaner.alpaca.framework.utils.validate;
     12 
     13 import java.awt.Color;
     14 import java.awt.Font;
     15 import java.awt.Graphics;
     16 import java.awt.Graphics2D;
     17 import java.awt.image.BufferedImage;
     18 import java.io.FileOutputStream;
     19 import java.io.IOException;
     20 import java.io.OutputStream;
     21 import java.util.Date;
     22 import java.util.Random;
     23 
     24 import javax.imageio.ImageIO;
     25 
     26 /**
     27 * @Package:cn.ucaner.framework.utils   
     28 * @ClassName:ValidateCode   
     29 * @Description:   <p> [验证码生成工具.]可生成数字,大写,小写字母及三者混合类型的验证码.
     30 *  支持自定义验证码字符数量; 支持自定义验证码图片的大小; 支持自定义需排除的特殊字符;
     31 *  支持自定义干扰线的数量; 支持自定义验证码图文颜色</p>
     32 * @Author: - Jason
     33 * @CreatTime:2017年10月20日 下午4:04:15   
     34 * @Modify By:   
     35 * @ModifyTime:  
     36 * @Modify marker:   
     37 * @version    V1.0
     38  */
     39 public class ValidateCode {
     40     
     41     // 图片的宽度。  
     42     private int width = 160;
     43     // 图片的高度。  
     44     private int height = 40;
     45     // 验证码字符个数  
     46     private int codeCount = 5;
     47     // 验证码干扰线数  
     48     private int lineCount = 150;
     49     // 验证码  
     50     private String code = null;
     51     // 验证码图片Buffer  
     52     private BufferedImage buffImg = null;
     53 
     54     // 验证码范围,去掉0(数字)和O(拼音)容易混淆的(小写的1和L也可以去掉,大写不用了)  
     55     private char[] codeSequence = { '0',
     56             //            'B',
     57             //            'C',
     58             //            'D',
     59             //            'E',
     60             //            'F',
     61             //            'G',
     62             //            'H',
     63             //            'I',
     64             //            'J',
     65             //            'K',
     66             //            'L',
     67             //            'M',
     68             //            'N',
     69             //            'P',
     70             //            'Q',
     71             //            'R',
     72             //            'S',
     73             //            'T',
     74             //            'U',
     75             //            'V',
     76             //            'W',
     77             //            'X',
     78             //            'Y',
     79             //            'Z',
     80             '1',
     81             '2',
     82             '3',
     83             '4',
     84             '5',
     85             '6',
     86             '7',
     87             '8',
     88             '9' };
     89 
     90     /** 
     91     * @param width  图片宽 
     92     * @param height 图片高 
     93     */
     94     public ValidateCode(int width, int height) {
     95         this.width = width;
     96         this.height = height;
     97         this.createCode();
     98     }
     99 
    100     /** 
    101      * @param width     图片宽 
    102      * @param height    图片高 
    103      * @param codeCount 字符个数 
    104      * @param lineCount 干扰线条数 
    105      */
    106     public ValidateCode(int width, int height, int codeCount, int lineCount) {
    107         this.width = width;
    108         this.height = height;
    109         this.codeCount = codeCount;
    110         this.lineCount = lineCount;
    111         this.createCode();
    112     }
    113 
    114     public void createCode() {
    115         int x = 0, fontHeight = 0, codeY = 0;
    116         int red = 0, green = 0, blue = 0;
    117 
    118         x = width / ( codeCount + 2 );//每个字符的宽度(左右各空出一个字符)  
    119         fontHeight = height - 2;//字体的高度  
    120         codeY = height - 4;
    121 
    122         // 图像buffer  
    123         buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    124         Graphics2D g = buffImg.createGraphics();
    125         // 生成随机数  
    126         Random random = new Random();
    127         // 将图像填充为白色  
    128         g.setColor(Color.WHITE);
    129         g.fillRect(0, 0, width, height);
    130         // 创建字体,可以修改为其它的  
    131         Font font = new Font("Fixedsys", Font.PLAIN, fontHeight);
    132         //            Font font = new Font("Times New Roman", Font.ROMAN_BASELINE, fontHeight);  
    133         g.setFont(font);
    134 
    135         for (int i = 0; i < lineCount; i++) {
    136             // 设置随机开始和结束坐标  
    137             int xs = random.nextInt(width);//x坐标开始  
    138             int ys = random.nextInt(height);//y坐标开始  
    139             int xe = xs + random.nextInt(width / 8);//x坐标结束  
    140             int ye = ys + random.nextInt(height / 8);//y坐标结束  
    141 
    142             // 产生随机的颜色值,让输出的每个干扰线的颜色值都将不同。  
    143             red = random.nextInt(255);
    144             green = random.nextInt(255);
    145             blue = random.nextInt(255);
    146             g.setColor(new Color(red, green, blue));
    147             g.drawLine(xs, ys, xe, ye);
    148         }
    149 
    150         // randomCode记录随机产生的验证码  
    151         StringBuffer randomCode = new StringBuffer();
    152         // 随机产生codeCount个字符的验证码。  
    153         for (int i = 0; i < codeCount; i++) {
    154             String strRand = String.valueOf(codeSequence[random.nextInt(codeSequence.length)]);
    155             // 产生随机的颜色值,让输出的每个字符的颜色值都将不同。  
    156             red = random.nextInt(255);
    157             green = random.nextInt(255);
    158             blue = random.nextInt(255);
    159             g.setColor(new Color(red, green, blue));
    160             g.drawString(strRand, ( i + 1 ) * x, codeY);
    161             // 将产生的四个随机数组合在一起。  
    162             randomCode.append(strRand);
    163         }
    164         // 将四位数字的验证码保存到Session中。  
    165         code = randomCode.toString();
    166     }
    167 
    168     public void write(String path) throws IOException {
    169         OutputStream sos = new FileOutputStream(path);
    170         this.write(sos);
    171     }
    172 
    173     public void write(OutputStream sos) throws IOException {
    174         ImageIO.write(buffImg, "png", sos);
    175         sos.close();
    176     }
    177 
    178     public BufferedImage getBuffImg() {
    179         return buffImg;
    180     }
    181 
    182     public String getCode() {
    183         return code;
    184     }
    185 
    186     /** 
    187      * 测试函数,默认生成到d盘 
    188      * @param args 
    189      */
    190     public static void main(String[] args) {
    191         ValidateCode vCode = new ValidateCode(160, 40, 4, 150);
    192         try {
    193             String path = "D:/" + new Date().getTime() + ".png";
    194             System.out.println(vCode.getCode() + " >" + path);
    195             vCode.write(path);
    196         } catch (IOException e) {
    197             e.printStackTrace();
    198         }
    199     }
    200 
    201     /**
    202      * 验证码类型为仅数字 0~9
    203      */
    204     public static final int TYPE_NUM_ONLY = 0;
    205 
    206     /**
    207      * 验证码类型为仅字母,即大写、小写字母混合
    208      */
    209     public static final int TYPE_LETTER_ONLY = 1;
    210 
    211     /**
    212      * 验证码类型为数字、大写字母、小写字母混合
    213      */
    214     public static final int TYPE_ALL_MIXED = 2;
    215 
    216     /**
    217      * 验证码类型为数字、大写字母混合
    218      */
    219     public static final int TYPE_NUM_UPPER = 3;
    220 
    221     /**
    222      * 验证码类型为数字、小写字母混合
    223      */
    224     public static final int TYPE_NUM_LOWER = 4;
    225 
    226     /**
    227      * 验证码类型为仅大写字母
    228      */
    229     public static final int TYPE_UPPER_ONLY = 5;
    230 
    231     /**
    232      * 验证码类型为仅小写字母
    233      */
    234     public static final int TYPE_LOWER_ONLY = 6;
    235 
    236     /**
    237      * 生成验证码字符串
    238      * 
    239      * @param type
    240      *            验证码类型,参见本类的静态属性
    241      * @param length
    242      *            验证码长度,大于0的整数
    243      * @param exChars
    244      *            需排除的特殊字符(仅对数字、字母混合型验证码有效,无需排除则为null)
    245      * @return 验证码字符串
    246      */
    247     public static String generateTextCode(int type, int length, String exChars) {
    248 
    249         if (length <= 0) {
    250             return "";
    251         }
    252         StringBuffer code = new StringBuffer();
    253         int i = 0;
    254         Random r = new Random();
    255 
    256         switch (type) {
    257 
    258         // 仅数字
    259         case TYPE_NUM_ONLY:
    260             while (i < length) {
    261                 int t = r.nextInt(10);
    262                 // 排除特殊字符
    263                 if (exChars == null || exChars.indexOf(t + "") < 0) {
    264                     code.append(t);
    265                     i++;
    266                 }
    267             }
    268             break;
    269 
    270         // 仅字母(即大写字母、小写字母混合)
    271         case TYPE_LETTER_ONLY:
    272             while (i < length) {
    273                 int t = r.nextInt(123);
    274                 if ( ( t >= 97 || ( t >= 65 && t <= 90 ) ) && ( exChars == null || exChars.indexOf((char) t) < 0 )) {
    275                     code.append((char) t);
    276                     i++;
    277                 }
    278             }
    279             break;
    280 
    281         // 数字、大写字母、小写字母混合
    282         case TYPE_ALL_MIXED:
    283             while (i < length) {
    284                 int t = r.nextInt(123);
    285                 if ( ( t >= 97 || ( t >= 65 && t <= 90 ) || ( t >= 48 && t <= 57 ) ) && ( exChars == null || exChars.indexOf((char) t) < 0 )) {
    286                     code.append((char) t);
    287                     i++;
    288                 }
    289             }
    290             break;
    291 
    292         // 数字、大写字母混合
    293         case TYPE_NUM_UPPER:
    294             while (i < length) {
    295                 int t = r.nextInt(91);
    296                 if ( ( t >= 65 || ( t >= 48 && t <= 57 ) ) && ( exChars == null || exChars.indexOf((char) t) < 0 )) {
    297                     code.append((char) t);
    298                     i++;
    299                 }
    300             }
    301             break;
    302 
    303         // 数字、小写字母混合
    304         case TYPE_NUM_LOWER:
    305             while (i < length) {
    306                 int t = r.nextInt(123);
    307                 if ( ( t >= 97 || ( t >= 48 && t <= 57 ) ) && ( exChars == null || exChars.indexOf((char) t) < 0 )) {
    308                     code.append((char) t);
    309                     i++;
    310                 }
    311             }
    312             break;
    313 
    314         // 仅大写字母
    315         case TYPE_UPPER_ONLY:
    316             while (i < length) {
    317                 int t = r.nextInt(91);
    318                 if ( ( t >= 65 ) && ( exChars == null || exChars.indexOf((char) t) < 0 )) {
    319                     code.append((char) t);
    320                     i++;
    321                 }
    322             }
    323             break;
    324 
    325         // 仅小写字母
    326         case TYPE_LOWER_ONLY:
    327             while (i < length) {
    328                 int t = r.nextInt(123);
    329                 if ( ( t >= 97 ) && ( exChars == null || exChars.indexOf((char) t) < 0 )) {
    330                     code.append((char) t);
    331                     i++;
    332                 }
    333             }
    334             break;
    335         default:
    336             break;
    337         }
    338 
    339         return code.toString();
    340     }
    341 
    342     /**
    343      * 已有验证码,生成验证码图片
    344      * 
    345      * @param textCode
    346      *            文本验证码
    347      * @param width
    348      *            图片宽度
    349      * @param height
    350      *            图片高度
    351      * @param interLine
    352      *            图片中干扰线的条数
    353      * @param randomLocation
    354      *            每个字符的高低位置是否随机
    355      * @param backColor
    356      *            图片颜色,若为null,则采用随机颜色
    357      * @param foreColor
    358      *            字体颜色,若为null,则采用随机颜色
    359      * @param lineColor
    360      *            干扰线颜色,若为null,则采用随机颜色
    361      * @return 图片缓存对象
    362      */
    363     public static BufferedImage generateImageCode(String textCode, int width, int height, int interLine, boolean randomLocation, Color backColor,
    364             Color foreColor, Color lineColor) {
    365 
    366         BufferedImage bim = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    367         Graphics g = bim.getGraphics();
    368 
    369         // 画背景图
    370         g.setColor(backColor == null ? getRandomColor() : backColor);
    371         g.fillRect(0, 0, width, height);
    372 
    373         // 画干扰线
    374         Random r = new Random();
    375         if (interLine > 0) {
    376 
    377             int x = 0, y = 0, x1 = width, y1 = 0;
    378             for (int i = 0; i < interLine; i++) {
    379                 g.setColor(lineColor == null ? getRandomColor() : lineColor);
    380                 y = r.nextInt(height);
    381                 y1 = r.nextInt(height);
    382 
    383                 g.drawLine(x, y, x1, y1);
    384             }
    385         }
    386 
    387         // 写验证码
    388 
    389         // g.setColor(getRandomColor());
    390         // g.setColor(isSimpleColor?Color.BLACK:Color.WHITE);
    391 
    392         // 字体大小为图片高度的80%
    393         int fsize = (int) ( height * 0.8 );
    394         int fx = height - fsize;
    395         int fy = fsize;
    396 
    397         g.setFont(new Font("Default", Font.PLAIN, fsize));
    398 
    399         // 写验证码字符
    400         for (int i = 0; i < textCode.length(); i++) {
    401             // 每个字符高低是否随机
    402             fy = randomLocation ? (int) ( ( Math.random() * 0.3 + 0.6 ) * height ) : fy;
    403             g.setColor(foreColor == null ? getRandomColor() : foreColor);
    404             g.drawString(textCode.charAt(i) + "", fx, fy);
    405             fx += fsize * 0.9;
    406         }
    407 
    408         g.dispose();
    409 
    410         return bim;
    411     }
    412 
    413     /**
    414      * 生成图片验证码
    415      * 
    416      * @param type
    417      *            验证码类型,参见本类的静态属性
    418      * @param length
    419      *            验证码字符长度,大于0的整数
    420      * @param exChars
    421      *            需排除的特殊字符
    422      * @param width
    423      *            图片宽度
    424      * @param height
    425      *            图片高度
    426      * @param interLine
    427      *            图片中干扰线的条数
    428      * @param randomLocation
    429      *            每个字符的高低位置是否随机
    430      * @param backColor
    431      *            图片颜色,若为null,则采用随机颜色
    432      * @param foreColor
    433      *            字体颜色,若为null,则采用随机颜色
    434      * @param lineColor
    435      *            干扰线颜色,若为null,则采用随机颜色
    436      * @return 图片缓存对象
    437      */
    438     public static BufferedImage generateImageCode(int type, int length, String exChars, int width, int height, int interLine, boolean randomLocation,
    439             Color backColor, Color foreColor, Color lineColor) {
    440         String textCode = generateTextCode(type, length, exChars);
    441         BufferedImage bim = generateImageCode(textCode, width, height, interLine, randomLocation, backColor, foreColor, lineColor);
    442 
    443         return bim;
    444     }
    445 
    446     /**
    447      * 产生随机颜色
    448      * 
    449      * @return
    450      */
    451     private static Color getRandomColor() {
    452         Random r = new Random();
    453         Color c = new Color(r.nextInt(255), r.nextInt(255), r.nextInt(255));
    454         return c;
    455     }
    456 
    457 }
  • 相关阅读:
    ZOJ 3642 多重匹配 离散化.cpp
    POJ 1840 Eqs.cpp 【 Hash 】
    Hdu 4293 DP
    Hlg 1407 【最小点权覆盖】.cpp
    Hdu 3605 多重匹配
    POJ 2195 【二分图最佳匹配】.cpp
    Hdu 4292 Food.cpp 最大流+拆点
    POJ 3469 【最小割】.cpp
    limit_choices_to a value on a field in the same model Google Groups
    Django: limit_choices_to (Is this correct) Stack Overflow
  • 原文地址:https://www.cnblogs.com/jasonandy/p/9184857.html
Copyright © 2020-2023  润新知