验证码生成工具

验证码生成工具

  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 }

 

posted @ 2018-06-14 20:29  安以北往南  阅读(1080)  评论(0编辑  收藏  举报