概要

  最近项目需要用java实现输出随机验证码图片到前台,正好有机会接触下java的绘图类,完成需求后也有时间做个总结,写篇随笔记录下也希望能帮助到有同样需求的人!

需求流程图

1.生成随机数

  在java中生成随机数无非就是调用Random的api,但为了后续更好的实用,应该分成多种组合以适应需求的变化,应将生成随机数的个数和类型组合还有排除字符抽取成参数,这个也比较简单,没有什么难度,就直接贴上代码

 /**
* 生成随机验证码
* @param type 类型
* @param length 长度
* @param exChars 排除的字符
* @return
*/
public static String getRandomCode(int type,int length,String exChars){
      case TYPE_NUM_CHAR://数字+(大小写)字母
while(i<length){
int t=random.nextInt(123);
if((t>=97||(t>=65&&t<=90)||(t>=48&&t<=57))&&(exChars==null||exChars.indexOf((char)t)<0)){
sb.append((char)t);
i++;
}
}
break; }

2.绘制图片

  绘制图片是重点也是难点,老实说我之前都没用过BufferedImage、Graphics、Color等对象,都是从度娘处脑补并结合帖子写出来的输出图片

  1)创建BufferedImage对象

    如果把BufferedImage比作是画板,那么Graphics就是画纸,这样比较好理解,后续的操作都是在这画纸上进行的

     BufferedImage image = new BufferedImage(width,height,BufferedImage.TYPE_INT_RGB);
    Graphics g = image.getGraphics();
    //随机操作对象
    Random r=new Random();

  2)绘制背景

   Graphics有个setColor()方法,可理解为画笔,在绘制任何东西前要选好画笔,即颜色,然后调用fillRect()进行轮廓的绘制,后续的绘制范围不会超过这个轮廓

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

  3)绘制干扰线

  调用drawLine画直线,绘制不超过interLine条干扰线

       if(interLine>0){
int x=r.nextInt(4),y=0;
int x1=width-r.nextInt(4),y1=0;
for(int i=0;i<interLine;i++){
g.setColor(lineColor==null?getRandomColor():lineColor);
y=r.nextInt(height-r.nextInt(4));
y1=r.nextInt(height-r.nextInt(4));
g.drawLine(x,y,x1,y1);
}
}

  4)写验证码

    写验证码时调用drawString()方法,为了不整整齐齐而且重叠的写,应将每个字符的高度和水平位置随机,重点在于每绘制完一个字符后,需将画笔的水平坐标往右边移动一定的位置,这里我用了依据宽度浮动,可不必照搬这里的,有合适的算法就行

      int fsize=(int)(height*0.8);//字体大小为图片高度的80%
int fx=0;
int fy=fsize;
g.setFont(new Font(Font.SANS_SERIF,Font.PLAIN,fsize));
//写字符
for(int i=0;i<textCode.length();i++){
fy=randomLocation?(int)((Math.random()*0.3+0.6)*height):fy;//每个字符高低是否随机
g.setColor(foreColor==null?getRandomColor():foreColor);
g.drawString(textCode.charAt(i)+"",fx,fy);
fx+=(width / textCode.length()) * (Math.random() * 0.3 + 0.8); //依据宽度浮动
   }

  5)扭曲图片

    图片的扭曲就是将图片水平和垂直按不同比例平移,copyArea()方法简单明了,直接是复制区域,也是同个意识

      //扭曲图片
shearX(g, width, height, backColor);
shearY(g, width, height, backColor);
private static void shearX(Graphics g, int w1, int h1, Color color) {
Random random=new Random();
int period = 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
          + (2.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) {
Random random=new Random();
int period = random.nextInt(40) + 10; // 50; boolean borderGap = true;
int frames = 20;
int phase = random.nextInt(2);
for (int i = 0; i < w1; i++) {
double d = (double) (period >> 1)
* Math.sin((double) i / (double) period
+ (2.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);
} } }

   6)添加噪点

    噪点的添加实质上就是在画纸上没有规律的点点点...,所以用随机颜色随机位置来执行image.setRGB()方法最合适了

      float yawpRate = 0.05f;// 噪声率
int area = (int) (yawpRate * width * height);//噪点数量
for (int i = 0; i < area; i++) {
int xxx = r.nextInt(width);
int yyy = r.nextInt(height);
int rgb = getRandomColor().getRGB();
image.setRGB(xxx, yyy, rgb);
}

  7)封笔

  以上一切画完之后,下一步就是封笔了,思来想去这样表达最合适,绘制完之后就是放好笔,收起画纸,这里就是返回BufferedImage对象

         g.dispose();
return image;

 输出目标位置

  1)输出文件

  这里写了一个简单的测试类,将图片输出成文件

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

    效果图:

    

  2)输出流

    输出到流中也是用到和到文件中的方法,根据业务保存到目标位置即可

     public static void outputStream(HttpServletRequest request,HttpServletResponse response){
try {
// 设置浏览器不缓存本页
response.addHeader("Pragma", "no-cache");
response.addHeader("Cache-Control", "no-cache");
response.addHeader("Expires", "0");
// 生成验证码,写入用户session
String verifyCode = CodeUtils.getRandomCode(CodeUtils.TYPE_NUM_CHAR, 4, null);
request.getSession().setAttribute("imageVerify", verifyCode);
// 输出验证码给客户端
response.setContentType("image/jpeg");
BufferedImage bim = ImageUtils
.getImageFromCode(verifyCode, 47, 18, 3, true,
Color.WHITE, Color.BLACK, null);
ImageIO.write(bim, "JPEG", response.getOutputStream()); } catch (Exception e) {
}
return null;
}

总结

  也没有比较深入的去分析绘制类,有需求可以通过调整位置参数来实现自己要的效果

java生成简单验证码图片的更多相关文章

  1. java生成随机验证码图片

    import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; i ...

  2. java 生成简单word(利用Itext工具),生成简单Excel,以及下载笔记

    1.java 生成简单word(包含图片表格) pom中加入itext 相关依赖 <dependency> <groupId>com.lowagie</groupId&g ...

  3. struts2生成随机验证码图片

    之前想做一个随机验证码的功能,自己也搜索了一下别人写的代码,然后自己重新用struts2实现了一下,现在将我自己实现代码贴出来!大家有什么意见都可以指出来! 首先是生成随机验证码图片的action: ...

  4. java生成汉字验证码

    java实现的汉字输入验证码,主要包含两个类,一个是生成验证码,一个是判断验证码输入是否正确,实现原理非常简单,将汉字和干扰线生成图片并将汉字保存到session,前台获取每次生成验证码图片并用文本框 ...

  5. Java生成随机验证码

    package com.tg.snail.core.util; import java.awt.Color; import java.awt.Font; import java.awt.Graphic ...

  6. java生成简单Excel工作薄

    前言: 代码都是建立在实际需求上的,上周做完一个调外部电影券接口的项目,这周产品又要excel表格,大致内容为:券所属影院.图片URL.等信息制作为excel表格,把每次同步过来的数据给他分析. jx ...

  7. 如何用java生成随机验证码

     1.VerifyCode 类:   1 package com.HRuinger.enity;                          ImageIO.write(image, " ...

  8. java生成图形验证码

    效果图 import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.image.Buf ...

  9. Python利用PIL生成随机验证码图片

    安装pillow: pip install pillow PIL中的Image等模块提供了创建图片,制作图片的功能,大致的步骤就是我们利用random生成6个随机字符串,然后利用PIL将字符串绘制城图 ...

随机推荐

  1. Mysql存储

    BEGIN # 统计视频使用的模板数 UPDATE VideoTemplate vt INNER JOIN ( SELECT TemplateId, COUNT(TemplateId) AS Tota ...

  2. 前端代理----whistle

    场景一:如何将本地的请求代理到服务器上(如果接口没有校验登陆的情况) 最简单的方法:在项目文件中找到webpack开发环境的配置文件,配置devServer对象 devServer: { conten ...

  3. memcache 杂记

    它是一个一个高性能的分布式内存对象缓存系统. 端口号 11211 目前被许多网站使用以提升网站的访问速度,尤其对于一些大型的.  需要频繁访问数据库的网站访问速度提升效果十分显著 根据一个sql取出的 ...

  4. Codeforces 1105C: Ayoub and Lost Array(递推)

    time limit per test: 1 second memory limit per test: 256 megabytes input: standard input output: sta ...

  5. [Java Web学习]JDBC事务处理

    1. Spring中加入数据库的bean <bean id="dataSource" class="org.apache.commons.dbcp.BasicDat ...

  6. Javascript 2.9

    对象:属性和方法属性:隶属于某个特定对象的变量方法:只有某个特定对象才能调用的函数 对象和方法都用"."来访问: Object.property Object.method() 由 ...

  7. nodejs-- vuex中mapActions

    mapActions() 返回的是一个对象, 用了 ... 扩展符后,才可以放进一个对象里,和其他组件内定义的 method 在同一个 methods 对象. { methods: mapAction ...

  8. js 创建标签执行

    <script type="text/javascript"> var _maq = _maq || []; _maq.push('_setAccount', 'F20 ...

  9. pl/sql oracle数据库中文数据显示异常或者不能使用中文查询的解决办法

    1首先我们需要找到pl/sql developer 目录 然后在该目录下 创建一个bat文件 在文件中定义 set NLS_LANG=AMERICAN_AMERICA.UTF8start PLSQLD ...

  10. 【配置阿里云 I】申请配置阿里云服务器,并部署IIS和开发环境,项目上线经验

    https://blog.csdn.net/vapaad1/article/details/78769520 最近一年在实验室做web后端开发,涉及到一些和服务器搭建及部署上线项目的相关经验,写个帖子 ...