概要

  最近项目需要用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. go chan 入门代码

    package main import ( "fmt" "sync" "time" ) // 生产数据 func producer(num ...

  2. SpringSecurity身份验证基础入门

    对于没有访问权限的用户需要转到登录表单页面.要实现访问控制的方法多种多样,可以通过Aop.拦截器实现,也可以通过框架实现(如:Apache Shiro.Spring Security). pom.xm ...

  3. Python变量和常量

    1.什么是变量 变量:核心在于变和量儿字,变->变化,量->状态如何定义? x=1 变量名 变量赋值符号:= 变量值:1 其中变量名又称为标识符: 1. 可以是字母,数字,下划线的任意组合 ...

  4. 批量镜像locator(比如表情模板)

    #外挂   镜像loc     前缀  lf  镜像给   rt   选中其中一个会镜像另一个 myPrefix='lf_'myMdf='rt_' myselectLoc=mc.ls(sl=1)for ...

  5. Jenkins可持续集成项目搭建——配置Jenkins基本设置 & 运行脚本报错点

    一.系统管理->全局工具配置:配置JDK.GIT: 二.项目配置-部署源码管理的远程地址 三.项目配置-构建触发器(以Windows平台举例) 构建项目时,会自动分配一个运行空间(D:\Prog ...

  6. shiro注解

    shiro注解权限控制-5个权限注解 RequiresAuthentication: 使用该注解标注的类,实例,方法在访问或调用时,当前Subject必须在当前session中已经过认证. Requi ...

  7. Spark:DataFrame批量导入Hbase的两种方式(HFile、Hive)

    Spark处理后的结果数据resultDataFrame可以有多种存储介质,比较常见是存储为文件.关系型数据库,非关系行数据库. 各种方式有各自的特点,对于海量数据而言,如果想要达到实时查询的目的,使 ...

  8. C++中的内部类

    1.内部类的概念 如果一个类定义在另一个类的内部,这个内部类就叫做内部类.注意此时这个内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去调用内部类.外部类对内部类没有任何优越的访问权限. ...

  9. Python Faker的使用(1):基础使用方法与函数速查,生成随机数据

    在软件需求.开发.测试过程中,有时候需要使用一些测试数据,针对这种情况,我们一般要么使用已有的系统数据,要么需要手动制造一些数据. 在手动制造数据的过程中,可能需要花费大量精力和工作量,现在好了,有一 ...

  10. stolon cloud native postgresql 高可用方案

    stolon方案与patroni 类似,是一个新的pg ha 方案 包含的组件 keeper:它管理一个PostgreSQL实例,汇聚到由领导者sentinel计算的clusterview. sent ...