用java生成gif格式的验证码

图片水印
placeholder image
admin 发布于:2013-10-31 10:18:00
阅读:loading

jsp验证码网上一搜一大堆,早些时候我收藏的一个(就是那个项目中最常见的那种)验证码(给个图一看便知图片,一个servlet搞定,但昨天无意中在网上看到gif的验证码的一篇文章,于是就找了找java生成gif图片相关的资源,发现真的出奇的少,后来终于找到了一个博文简短几行代码就生成gif图片的,评价还是很不错的,于是把这些代码拷贝出来之后发现编译不通过,是少了个AnimatedGifEncoder类,快捷键提示也提示不出来,心里想着,什么瘠薄例子撒,代码各种不全,也不做个代码运行环境的介绍,呵呵,网络上就是这样。接着就是google了一下这个类,找到了它的源码,虽然不是很懂的样子但还是拷贝了下来存储在本地工程当中,结果又发现编译不通过,又有两处报红XX的地方,仔细查看才知又少了几个类。。。。。。此处省略吧,换个话题。
        在这里通过这个实践跟大家分享两个经验吧。
一、eclipse强大的Shift + Alt + A 快捷键功能。
    此快捷键的用途

    我们可谓是常常从网上拷贝代码到eclipse当中,大多数的博客或日志中的代码块都是有行号的,直接选择代码复制出来的代码肯定是不能使用的,必须去掉开头的行号和.才行,记得最开始不知道此快捷键的时候鄙人是一行一行删除的,后来也是从一个同事那儿知道的,慢慢慢慢的广泛的使用起来(鄙人自己广泛使用)、、、、解释下此快捷键的用途吧,按下此快捷键之后,可以像截图一样选择无规律的一片代码,然后可以对这块代码进行删除、复制等等。见下图:

代码.gif

二、如何快速的找到不熟悉的类文件所在地以及其源码。
    快速查找不熟悉的文件的源代码
    解决这个问题,我推荐这个网站   http://www.docjar.com/ ; 专门查找jar文件的,当然也能找到源代码和javadoc,比如AnimatedGifEncoder.java文件中还需要找到NeuQuant.java和LZWEncoder.java,我都是在这里找到的。
=========分割一样,以下重点介绍下gif的验证码=========
 允许我把这几个文件归以下类吧,将他们称之为一个组件吧(网上也有人说是借助于洋人写的类),先根据一个最基础的例子来熟悉以下生成gif的代码吧。
三、查看简单的代码示例燃起对这个知识点的兴趣吧
TestCreateGif.java(不要纠结于我的类命名,需要用到的AnimatedGifEncoder文件需注意源代码下载
 

 

package com.gif;

import java.awt.image.BufferedImage;

import java.io.File;

import javax.imageio.ImageIO;

 

public class TestCreateGif {

   final static String path = "f:\\tt\\gifdemo\\";
 

   public static void create() throws Exception {

      BufferedImage fileA = ImageIO.read(new File(path"a.jpg"));

      BufferedImage fileB = ImageIO.read(new File(path"b.jpg"));

      BufferedImage fileC = ImageIO.read(new File(path"c.jpg"));

      AnimatedGifEncoder gif = new AnimatedGifEncoder();

      gif.setRepeat(0);//设置是否重复切换

      gif.start("f:\\tt\\gifdemo\\demo.gif");

      gif.setDelay(500);//设置每次切换时的时间间隔,单位毫秒

      gif.addFrame(fileA);//添加一帧的图片

      gif.setDelay(500);

      gif.addFrame(fileB);

      gif.setDelay(500);

      gif.addFrame(fileC);

      boolean result = gif.finish();

      System.out.println(result);

   }

   public static void main(String[] args) throws Exception {

      create();

   }

}

 

代码就这么简单易懂,看下运行结果吧。

以上代码中的a.jpg,b.jpg,c.jpg原图为:image.png

生成的demo.gif原为:demo.gif

四、改造最开始提到的那种最简单的验证码吧,将之改造成gif动态的
            有了上面的小例子,相信改造下原来的版本应该不难吧, 直接给出改造后的代码吧。 

package com.gif;

import java.awt.Color;

import java.awt.Font;

import java.awt.Graphics;

import java.awt.image.BufferedImage;

import java.util.Arrays;

import java.util.Random;

/**

 * 

 * @author chendd

 *

 */

public class TestCreateGif2Old {

    /**

     * 4

     */

    final static String RANDOM_CHAR = "abcdefijklmnopqrstuvwxyzABCDEFIJKLMNOPQRSTUVWXYZ012356789";

    /**

     *  4 

     */

    final static int CODE_LENS = 4;

    /**

     * gif

     */

    final static int CHANGE_COUNT = 3;

    /**

     * @param args

     * @throws Exception

     */

    public static void main(String args[]) throws Exception {

        long start = System.currentTimeMillis();

        create("f:\\tt\\gifdemo\\abcdefg.gif");

        long end = System.currentTimeMillis();

        System.out.println("" + (end - start) + "ms");

    }

    /**

     * 

     * @throws Exception

     */

    public static void create(String filePath) throws Exception {

        //N

        int width = CODE_LENS * 15 - CODE_LENS * 15 / 10 + 6, height = 20;

        // 

        AnimatedGifEncoder gifFrame = new AnimatedGifEncoder();

        BufferedImage frame;

        //servlet使gif.start(fos);

        gifFrame.start(filePath);//

        gifFrame.setRepeat(0);//01

        gifFrame.setDelay(600);//600

        // N 

        char[] randCodes = new char[CODE_LENS];

        for(int i = 0 ; i < CODE_LENS ; i ++){

            randCodes[i] = getRandomChar();

        }

        for(int i = 0 ; i < CHANGE_COUNT ; i ++){

            frame = graphicsImage(randCodes , width, height);

            gifFrame.addFrame(frame);

        }

        gifFrame.finish();

        System.out.println("code" + Arrays.toString(randCodes));

        // servlet使codesession......

    }

    /**

     * 

     * @param randCodes

     * @param width

     * @param height

     * @return

     */

    private static BufferedImage graphicsImage(char[] randCodes , int width, int height) {

        Random random = new Random();

        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        // 

        Graphics g = image.getGraphics();

        // 

        g.setColor(getRandColor(200, 250));

        g.fillRect(0, 0, width, height);

        // 

        g.setFont(new Font("Times New Roman", Font.CENTER_BASELINE, 18));

        // 

        // g.setColor(new Color());

        // g.drawRect(0,0,width-1,height-1);

        // 155线使

        g.setColor(getRandColor(160, 200));

        for (int i = 0; i < 40; i++) {

            int x = random.nextInt(width);

            int y = random.nextInt(height);

            int xl = random.nextInt(12);

            int yl = random.nextInt(12);

            g.drawLine(x, y, x + xl, y + yl);

        }

        // (4)

        for (int i = 0; i < randCodes.length; i++) {

            // 

            g.setColor(new Color(20 + random.nextInt(110), 20 + random

                    .nextInt(110), 20 + random.nextInt(110)));

            // 

            g.drawString(String.valueOf(randCodes[i]), 13 * i + 6, 16);

        }

        // 

        g.dispose();

        return image;

    }

    /**

     * 

     * @param fc

     * @param bc

     * @return

     */

    private static Color getRandColor(int fc, int bc) {

        Random random = new Random();

        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);

    }

    /**

     * 

     * @return

     */

    private static Character getRandomChar() {

        int lens = RANDOM_CHAR.length();

        int randomInt = new Random().nextInt(lens);

        Character c = RANDOM_CHAR.charAt(randomInt);

        return c;

    }

}

 控制台输出结果如下:
        生成的code为:[N, N, 3, 3]
        所用时间为:566ms

 生成的图片文件如下:
         调用了好几次,竟然能生成出两个都一样的验证码,那就用它了,生成的图为:效果图-含水印.gif

五、源码下载
     源码下载还是沿承了内涵图片的方式,将上图中的NN33所在的图片存储至本地,然后使用压缩包工具打开,即可看到src-code.zip文件。有什么问题也可以直接点击下图的联系我。

@2013-12-18添加
        最近整改的一个项目中,其也使用到了gif的验证码,效果如下:效果图-含水印 (1).gif此图生成的代码在保存图片时被我修改我,我将延迟时间调大了一些,源码里面是100毫秒闪烁的),这种效果在看上去在安全性上更好一些的样子,但此处的效果貌似太闪了一些,个人觉得主要就是,闪烁效果在每次变化的时候,上面的字符基本都是3位数呈现的,如果用上面的代码来实现这种效果的话,相当于生成4帧的图片,每个图片中都显示当前字符长度的字符,即循环1次时生成1个字符的图片,循环第2次时生成2个字符的图片,一次类推(这里说下修改的原理,并为新手试验),导致用户在录入验证码时一眼看上去看不完全,至少我是得看4眼,眼在每个字符上停留一眼,谈谈意见而已,不喜勿怒。
        另外我上面的代码中排除了感觉不好的数字4,发现其里面排除了O和I这些,这些都是容易混淆的字符,挺好的。
@2013-12-19添加
        Java学习室中也有这个源码,http://www.java3z.com/cwbwebhome/article/article3/3915.html?id=4895

上述许多内容已经过时和过期了,留存本篇文章仅为方便个人查看,原始文章的信息参考:

原始链接:https://www.chendd.cn/information/viewInformation/other/100.a

最后更新:2013-10-31 10:18:00

访问次数:586

评论次数:0

点赞个数:1,[路过一下:1]

 点赞


 发表评论

当前回复:作者

 评论列表


留言区