概要

  最近项目需要用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. vue 配合vue-resource调用接口,获取数据

    1.先用node+express+mysql简单配置一下后台 const express = require('express');const mysql = require('mysql');con ...

  2. Java基于opencv实现图像数字识别(三)—灰度化和二值化

    Java基于opencv实现图像数字识别(三)-灰度化和二值化 一.灰度化 灰度化:在RGB模型中,如果R=G=B时,则彩色表示灰度颜色,其中R=G=B的值叫灰度值:因此,灰度图像每个像素点只需一个字 ...

  3. Linux系统一些常用命令(持续增加)

    这些命令什么的全是从网上找的,防止忘记,留下来备忘 1.linux服务器如何从另一台服务器拷东西:可以用scp命令scp user@remote.machine:/remote/path /local ...

  4. 【笔记】 laravel 的路由

    路由简介 : 请求对应着路由,将用户的请求转发给相应的程序进行处理 建立URL与程序之间的映射 Laravel中的请求类型:get.post.put.patch.delete   Route::get ...

  5. 冰水挑战 HDU - 6495

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6495 题解:DP!!! dp[i][j] 表示前i个挑战,接受了j个剩余的最大体力,最后输出体力大于0 ...

  6. Linux安装MySQL_5.6

    E&T: CentOS_7.4 64位; mysql-5.6.42-linux-glibc2.12-x86_64.tar; Xftp5; Xshell5; P1.下载Linux环境下的MySQ ...

  7. jquery案例

    调用js成员 <!DOCTYPE html><html xmlns="http://www.w3.org/1999/xhtml"><head>& ...

  8. python中使用if __name__ == '__main__':

    引子 在python中,假设在一个test1.py的模块中定义了一个foo函数,然后调用函数foo进行测试的时候会产生一个内存空间.当你把这个模块导入到test2.py模块中,接下来如果在test2. ...

  9. 2018-2019-2 网络对抗技术 20165308 Exp2 后门原理与实践

    2018-2019-2 网络对抗技术 20165308 Exp2 后门原理与实践 1.实验内容 (3.5分) (1)使用netcat获取主机操作Shell,cron启动 (0.5分) (2)使用soc ...

  10. MGR实现分析 - 成员管理与故障恢复实现

    MySQL Group Replication(MGR)框架让MySQL具备了自动主从切换和故障恢复能力,举single primary(单主)模式为例,primary作为主节点对外提供读写服务,是唯 ...