java生成簡單驗證碼圖片

概要java

  最近項目須要用java實現輸出隨機驗證碼圖片到前臺,正好有機會接觸下java的繪圖類,完成需求後也有時間作個總結,寫篇隨筆記錄下也但願能幫助到有一樣需求的人!算法

需求流程圖api

1.生成隨機數瀏覽器

  在java中生成隨機數無非就是調用Random的api,但爲了後續更好的實用,應該分紅多種組合以適應需求的變化,應將生成隨機數的個數和類型組合還有排除字符抽取成參數,這個也比較簡單,沒有什麼難度,就直接貼上代碼緩存

 1 /**
 2      * 生成隨機驗證碼
 3      * @param type  類型
 4      * @param length   長度
 5      * @param exChars  排除的字符
 6      * @return
 7      */
 8     public static String getRandomCode(int type,int length,String exChars){
 9       case TYPE_NUM_CHAR://數字+(大小寫)字母
10             while(i<length){
11                 int t=random.nextInt(123);
12                 if((t>=97||(t>=65&&t<=90)||(t>=48&&t<=57))&&(exChars==null||exChars.indexOf((char)t)<0)){
13                     sb.append((char)t);
14                     i++;
15                 }
16             }
17             break;
18     
19

2.繪製圖片session

  繪製圖片是重點也是難點,老實說我以前都沒用過BufferedImage、Graphics、Color等對象,都是從度娘處腦補並結合帖子寫出來的輸出圖片app

  1)建立BufferedImage對象dom

    若是把BufferedImage比做是畫板,那麼Graphics就是畫紙,這樣比較好理解,後續的操做都是在這畫紙上進行的測試

1     BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
2     Graphics g = image.getGraphics();
3     //隨機操做對象
4     Random r=new Random();

  2)繪製背景字體

   Graphics有個setColor()方法,可理解爲畫筆,在繪製任何東西前要選好畫筆,即顏色,而後調用fillRect()進行輪廓的繪製,後續的繪製範圍不會超過這個輪廓

1         g.setColor(backColor==null?getRandomColor():backColor);
2         g.fillRect(0,0,width,height);

  3)繪製干擾線

  調用drawLine畫直線,繪製不超過interLine條幹擾線

 1       if(interLine>0){
 3             int x=r.nextInt(4),y=0;
 4             int x1=width-r.nextInt(4),y1=0;
 5             for(int i=0;i<interLine;i++){
 6                 g.setColor(lineColor==null?getRandomColor():lineColor);
 7                 y=r.nextInt(height-r.nextInt(4));
 8                 y1=r.nextInt(height-r.nextInt(4));
 9                 g.drawLine(x,y,x1,y1);
10             }
11         }

   4)寫驗證碼

    寫驗證碼時調用drawString()方法,爲了避免整整齊齊並且重疊的寫,應將每一個字符的高度和水平位置隨機,重點在於每繪製完一個字符後,需將畫筆的水平座標往右邊移動必定的位置,這裏我用了依據寬度浮動,可沒必要照搬這裏的,有合適的算法就行

 1      int fsize=(int)(height*0.8);//字體大小爲圖片高度的80%
 2         int fx=0;
 3         int fy=fsize;
 4         g.setFont(new Font(Font.SANS_SERIF,Font.PLAIN,fsize));
 5         //寫字符
 6         for(int i=0;i<textCode.length();i++){
 7             fy=randomLocation?(int)((Math.random()*0.3+0.6)*height):fy;//每一個字符高低是否隨機
 8             g.setColor(foreColor==null?getRandomColor():foreColor);
 9             g.drawString(textCode.charAt(i)+"",fx,fy);
10             fx+=(width / textCode.length()) * (Math.random() * 0.3 + 0.8); //依據寬度浮動
11        }

  5)扭曲圖片

    圖片的扭曲就是將圖片水平和垂直按不一樣比例平移,copyArea()方法簡單明瞭,直接是複製區域,也是同個意識

 

 1      //扭曲圖片
 2          shearX(g, width, height, backColor);
 3          shearY(g, width, height, backColor);    
 4          private static void shearX(Graphics g, int w1, int h1, Color color) {
 5          Random random=new Random();
 6          int period = 2;
 7   
 8          boolean borderGap = true;
 9          int frames = 1;
10         int phase = random.nextInt(2);
11  
12         for (int i = 0; i < h1; i++) {
13             double d = (double) (period >> 1)* Math.sin((double) i / (double) period 
14           + (2.2831853071795862D * (double) phase)/ (double) frames);
15             g.copyArea(0, i, w1, 1, (int) d, 0);
16             if (borderGap) {
17                 g.setColor(color);
18                 g.drawLine((int) d, i, 0, i);
19                 g.drawLine((int) d + w1, i, w1, i);
20             }
21         }
22  
23     }
24  
25     private static void shearY(Graphics g, int w1, int h1, Color color) {
26         Random random=new Random();
27         int period = random.nextInt(40) + 10; // 50;
28  
29         boolean borderGap = true;
30         int frames = 20;
31         int phase = random.nextInt(2);
32         for (int i = 0; i < w1; i++) {
33             double d = (double) (period >> 1)
34                     * Math.sin((double) i / (double) period
35                             + (2.2831853071795862D * (double) phase)/ (double) frames);
36             g.copyArea(i, 0, 1, h1, 0, (int) d);
37             if (borderGap) {
38                 g.setColor(color);
39                 g.drawLine(i, (int) d, i, 0);
40                 g.drawLine(i, (int) d + h1, i, h1);
41             }
42  
43         }
44  
45     }

 

   6)添加噪點

    噪點的添加實質上就是在畫紙上沒有規律的點點點...,因此用隨機顏色隨機位置來執行image.setRGB()方法最合適了

1      float yawpRate = 0.05f;// 噪聲率
2         int area = (int) (yawpRate * width * height);//噪點數量
3         for (int i = 0; i < area; i++) {
4             int xxx = r.nextInt(width);
5             int yyy = r.nextInt(height);
6             int rgb = getRandomColor().getRGB();
7             image.setRGB(xxx, yyy, rgb);
8         }

  7)封筆

  以上一切畫完以後,下一步就是封筆了,思來想去這樣表達最合適,繪製完以後就是放好筆,收起畫紙,這裏就是返回BufferedImage對象

1         g.dispose();
2         return image;    

 輸出目標位置

  1)輸出文件

  這裏寫了一個簡單的測試類,將圖片輸出成文件

 1 public static void main(String[] args) {
 2         String randomCode = CodeUtils.getRandomCode(CodeUtils.TYPE_NUM_CHAR, 4, null);
 3         System.out.println(randomCode);
 4         BufferedImage imageFromCode = ImageUtils.getImageFromCode(randomCode, 100, 50, 3, true, Color.WHITE, Color.BLACK, null);
 5          try {
 6             File file = new File("d:/test01.jpg");
 7             ImageIO.write(imageFromCode,"jpg",file);
 8             System.out.println("成功保存到:"+file.getAbsolutePath());
 9         } catch (IOException e) {
10             System.out.println("保存失敗");
11             e.printStackTrace();
12         } 
13         
14     }

    效果圖:

    

  2)輸出流

    輸出到流中也是用到和到文件中的方法,根據業務保存到目標位置便可

 1     public static void outputStream(HttpServletRequest request,HttpServletResponse response){
 2         try {
 3             // 設置瀏覽器不緩存本頁
 4             response.addHeader("Pragma", "no-cache");
 5             response.addHeader("Cache-Control", "no-cache");
 6             response.addHeader("Expires", "0");
 7             // 生成驗證碼,寫入用戶session
 8             String verifyCode = CodeUtils.getRandomCode(CodeUtils.TYPE_NUM_CHAR, 4, null);
 9             request.getSession().setAttribute("imageVerify", verifyCode);
10             // 輸出驗證碼給客戶端
11             response.setContentType("image/jpeg");
12             BufferedImage bim = ImageUtils
13                     .getImageFromCode(verifyCode, 47, 18, 3, true,
14                             Color.WHITE, Color.BLACK, null);
15             ImageIO.write(bim, "JPEG", response.getOutputStream());
16 
17         } catch (Exception e) {
18         }
19         return null;
20     }

總結

  也沒有比較深刻的去分析繪製類,有需求能夠經過調整位置參數來實現本身要的效果

相關文章
相關標籤/搜索