基于Java生成图片验证码的方法解析

作者:全村最野的狗 时间:2022-01-22 06:00:37 

使用Java生成图片验证码完全解析

在 Java 中开发图片验证码功能,您可以使用 Java 图形处理库,比如 Java Advanced Imaging (JAI) 或者 Java2D,来生成图片并将文本写入图片。具体实现方法如下:

  • 创建一个 BufferedImage 对象,并设置图片的宽度和高度。

  • 获取图片的 Graphics2D 对象,并设置文本的颜色和字体。

  • 在图片上绘制文本。

  • 对图片进行一些随机处理,比如加入干扰线、噪点等,以增加图片验证码的难度。

  • 将图片输出到浏览器,并设置相应的 Content-Type。或者将BufferedImage转为base64编码输出到浏览器。(本次统一输出到文件)

基于Java生成图片验证码的方法解析

下面是一个简单的示例代码,可以帮助您快速开始:

import java.awt.*;
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;

public class Captcha {
 public static void main(String[] args) throws Exception {
   int width = 100;
   int height = 40;

// 创建 BufferedImage 对象
   BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

// 获取图片的 Graphics2D 对象
   Graphics2D g = image.createGraphics();

// 设置文本的颜色和字体
   g.setColor(Color.WHITE);
   g.setFont(new Font("Arial", Font.BOLD, 20));

// 绘制文本
   g.drawString("Hello, World!", 10, 30);

// 释放 Graphics2D 对象
   g.dispose();

// 将图片输出到浏览器
   ImageIO.write(image, "jpeg", new File("captcha.jpeg"));
 }
}

注意事项

在您的应用中使用图片验证码功能时,需要注意以下几点:

  • 在生成图片验证码时,需要使用随机数生成文本内容,以保证每次生成的图片都是不同的。

  • 在生成图片时,需要使用足够复杂的算法来生成干扰线和噪点,以增加图片验证码的难度。

  • 在向用户展示图片验证码时,需要将图片的文本内容存储在服务器端,以便在用户提交表单时进行验证。

  • 在验证用户输入的图片验证码时,需要注意大小写敏感问题,并且需要考虑用户输入的可能存在的误差。

如何加入噪点

在 Java 中加入噪点可以使用随机数生成噪点的位置和颜色,然后使用 Graphics2D 的 drawLine() 方法在图片上绘制噪点。

基于Java生成图片验证码的方法解析

例如,下面的代码演示了如何在图片上随机绘制 100 个噪点:

import java.awt.*;
import java.awt.image.*;
import java.util.Random;

public class Captcha {
 public static void main(String[] args) throws Exception {
   int width = 100;
   int height = 40;

// 创建 BufferedImage 对象
   BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

// 获取图片的 Graphics2D 对象
   Graphics2D g = image.createGraphics();

// 设置文本的颜色和字体
   g.setColor(Color.WHITE);
   g.setFont(new Font("Arial", Font.BOLD, 20));

// 绘制文本
   g.drawString("Hello, World!", 10, 30);

// 创建随机数生成器
   Random rnd = new Random();

// 绘制噪点
   for (int i = 0; i < 100; i++) {
     int x = rnd.nextInt(width);
     int y = rnd.nextInt(height);
     g.drawLine(x, y, x, y);
   }

// 释放 Graphics2D 对象
   g.dispose();
 }
}

上面的代码中,我们使用了随机数生成噪点的位置和颜色,并使用 Graphics2D 的 drawLine() 方法在图片上绘制噪点。

如何生成干扰线

在 Java 中生成干扰线可以使用随机数生成干扰线的起始点和结束点,然后使用 Graphics2D 的 drawLine() 方法在图片上绘制干扰线。

基于Java生成图片验证码的方法解析

例如,下面的代码演示了如何在图片上随机绘制 10 条干扰线:

import java.awt.*;
import java.awt.image.*;
import java.util.Random;

public class Captcha {
 public static void main(String[] args) throws Exception {
   int width = 100;
   int height = 40;

// 创建 BufferedImage 对象
   BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

// 获取图片的 Graphics2D 对象
   Graphics2D g = image.createGraphics();

// 设置文本的颜色和字体
   g.setColor(Color.WHITE);
   g.setFont(new Font("Arial", Font.BOLD, 20));

// 绘制文本
   g.drawString("Hello, World!", 10, 30);

// 创建随机数生成器
   Random rnd = new Random();

// 绘制干扰线
   for (int i = 0; i < 10; i++) {
     int x1 = rnd.nextInt(width);
     int y1 = rnd.nextInt(height);
     int x2 = rnd.nextInt(width);
     int y2 = rnd.nextInt(height);
     g.drawLine(x1, y1, x2, y2);
   }

// 释放 Graphics2D 对象
   g.dispose();
 }
}

上面的代码中,我们使用了随机数生成干扰线的起始点和结束点,并使用 Graphics2D 的 drawLine() 方法在图片上绘制干扰线。到了这一步其实大多数OCR已经不能识别了。

什么样的算法生成噪点比较好

在生成噪点时,最重要的是要保证噪点数量足够多,以增加图片验证码的难度。您可以使用以下算法来生成噪点:

  • 在图片的所有像素点上随机绘制一定数量的噪点。这种方法可以保证噪点数量足够多,但会使图片变得很杂乱,不利于用户识别。

  • 在图片的一部分像素点上随机绘制噪点。这种方法可以使图片看起来清晰一些,但需要调整噪点的数量,以保证噪点数量足够多。

  • 使用图形生成算法生成噪点。这种方法可以生成较为复杂的噪点图形,但需要较多的计算资源。

最终选择哪种方法取决于您的需求和系统的性能。

在 Java 中使用图形生成算法生成噪点,可以使用 Java2D 库中的 Shape 接口和相关的实现类来生成各种图形。例如,使用 Ellipse2D 类可以生成椭圆形噪点,使用 Rectangle2D 类可以生成矩形噪点。

基于Java生成图片验证码的方法解析

下面是一个简单的示例代码,演示了如何使用图形生成算法生成噪点:

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.util.Random;

public class Captcha {
 public static void main(String[] args) throws Exception {
   int width = 100;
   int height = 40;

// 创建 BufferedImage 对象
   BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

// 获取图片的 Graphics2D 对象
   Graphics2D g = image.createGraphics();

// 设置文本的颜色和字体
   g.setColor(Color.WHITE);
   g.setFont(new Font("Arial", Font.BOLD, 20));

// 绘制文本
   g.drawString("Hello, World!", 10, 30);

// 创建随机数生成器
   Random rnd = new Random();

// 绘制噪点
   for (int i = 0; i < 100; i++) {
     Shape shape = new Ellipse2D.Double(rnd.nextDouble() * width, rnd.nextDouble() * height, rnd.nextDouble() * 5 + 1, rnd.nextDouble() * 5 + 1);
     g.fill(shape);
   }

// 释放 Graphics2D 对象
   g.dispose();
 }
}

验证码如何避免被ocr识别

为了避免验证码被 OCR (Optical Character Recognition, 光学字符识别) 软件识别,可以使用以下几种方法:

  • 增加噪点:在图片中加入噪点(如随机点、线条等),使 OCR 软件难以准确识别文本。

  • 斜放文本:将文本斜放,使 OCR 软件难以识别。

  • 改变字体:使用特殊的字体,使 OCR 软件难以识别。

  • 变换颜色:改变文本的颜色,使 OCR 软件难以识别。

  • 增加干扰元素:在图片中加入干扰元素(如干扰线、干扰图案等),使 OCR 软件难以准确识别文本。

如何斜放文本

单纯的斜放文本只能避免某一些OCR算法,最好是每个字符都倾斜不同的角度。并且保持不同的间距。

在 Java 中斜放文本可以使用 Graphics2D 的 rotate() 方法来旋转文本。例如,下面的代码演示了如何在图片上斜放文本:

基于Java生成图片验证码的方法解析

import java.awt.*;
import java.awt.image.*;

public class Captcha {
 public static void main(String[] args) throws Exception {
   int width = 100;
   int height = 40;

// 创建 BufferedImage 对象
   BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

// 获取图片的 Graphics2D 对象
   Graphics2D g = image.createGraphics();

// 设置文本的颜色和字体
   g.setColor(Color.WHITE);
   g.setFont(new Font("Arial", Font.BOLD, 20));

// 旋转文本
   g.rotate(Math.toRadians(30), width / 2, height / 2);

// 绘制文本
   g.drawString("Hello, World!", 10, 30);

// 释放 Graphics2D 对象
   g.dispose();
 }
}

上面的代码中,我们使用 Graphics2D 的 rotate() 方法将文本旋转了 30 度。注意,旋转角度使用的是弧度制,所以需要使用 Math.toRadians() 方法将角度转换为弧度。

四位图形验证码

实现一个支持图形干扰算法,斜放文本,使用特殊的字体,动态文本的颜色的四位图形验证码

基于Java生成图片验证码的方法解析

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.util.Random;

public class Captcha {
 private static final char[] CHARS = {
   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
   'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
   'U', 'V', 'W', 'X', 'Y', 'Z',
   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
   'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
   'u', 'v', 'w', 'x', 'y', 'z'
 };

private static Random rnd = new Random();

public static String generateText() {
   StringBuilder sb = new StringBuilder();
   for (int i = 0; i < 4; i++) {
     sb.append(CHARS[rnd.nextInt(CHARS.length)]);
   }
   return sb.toString();
 }

public static Color generateColor() {
   return new Color(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
 }

public static void main(String[] args) throws Exception {
   int width = 120;
   int height = 40;

// 创建 BufferedImage 对象
   BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

// 获取图片的 Graphics2D 对象
   Graphics2D g = image.createGraphics();

// 绘制背景
   g.setColor(Color.WHITE);
   g.fillRect(0, 0, width, height);

// 绘制文本
   String text = generateText();
   g.setFont(new Font("Arial", Font.BOLD, 20));
   g.setColor(generateColor());
   g.rotate(Math.toRadians(30), width / 2, height / 2);
   g.drawString(text, 10, 30);

// 绘制噪点
   for (int i = 0; i < 100; i++) {
     Shape shape = new Ellipse2D.Double(rnd.nextDouble() * width, rnd.nextDouble() * height, rnd.nextDouble() * 5 + 1, rnd.nextDouble() * 5 + 1);
     g.setColor(generateColor());
     g.fill(shape);
   }

// 绘制干扰线
   for (int i = 0; i < 5; i++) {
     g.setColor(generateColor());
     g.drawLine(rnd.nextInt(width), rnd.nextInt(height), rnd.nextInt(width), rnd.nextInt(height));
   }

// 释放 Graphics2D 对象
   g.dispose();

// 输出图片
   ImageIO.write(image, "PNG", new File("captcha.png"));
 }
}

上面的代码中,我们使用了 Ellipse2D 类生成椭圆形噪点,并使用随机数生成噪点的位置和大小。我们还使用了 drawLine() 方法生成干扰线,并使用随机数生成干扰线的位置和长度。

可以看到,虽然安全性提高了,但是辨识很困难。

调整噪点的透明度

在 Java 中调整噪点的透明度可以使用 AlphaComposite 类的静态方法 getInstance() 来创建 AlphaComposite 对象,然后使用 setComposite() 方法来设置透明度。例如,下面的代码演示了如何调整噪点的透明度:

基于Java生成图片验证码的方法解析

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.util.Random;

public class Captcha {
 private static final char[] CHARS = {
   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J',
   'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
   'U', 'V', 'W', 'X', 'Y', 'Z',
   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j',
   'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't',
   'u', 'v', 'w', 'x', 'y', 'z'
 };

private static Random rnd = new Random();

public static String generateText() {
   StringBuilder sb = new StringBuilder();
   for (int i = 0; i < 4; i++) {
     sb.append(CHARS[rnd.nextInt(CHARS.length)]);
   }
   return sb.toString();
 }

public static Color generateColor() {
   return new Color(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
 }

public static void main(String[] args) throws Exception {
   int width = 120;
   int height = 40;

// 创建 BufferedImage 对象
   BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

// 获取图片的 Graphics2D 对象
   Graphics2D g = image.createGraphics();

// 绘制背景
   g.setColor(Color.WHITE);
   g.fillRect(0, 0, width, height);

// 绘制文本
   String text = generateText();
   g.setFont(new Font("Arial", Font.BOLD, 20));
   g.setColor(generateColor());
   g.rotate(Math.toRadians(30), width / 2, height / 2);
   g.drawString(text, 10, 30);

// 调整噪点的透明度
   g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.5f));

// 绘制噪点
   for (int i = 0; i < 100; i++) {
     Shape shape = new Ellipse2D.Double(rnd.nextDouble() * width, rnd.nextDouble() * height, rnd.nextDouble() * 5 + 1, rnd.nextDouble() * 5 + 1);
     g.setColor(generateColor());
     g.fill(shape);
   }

// 绘制干扰线
   for (int i = 0; i < 5; i++) {
     g.setColor(generateColor());
     g.drawLine(rnd.nextInt(width), rnd.nextInt(height), rnd.nextInt(width), rnd.nextInt(height));
   }

// 释放 Graphics2D 对象
   g.dispose();

// 输出图片
   ImageIO.write(image, "PNG", new File("captcha.png"));
 }
}

来源:https://juejin.cn/post/7196266492269379643

标签:Java,图片,验证码
0
投稿

猜你喜欢

  • java 流与 byte[] 的互转操作

    2023-06-26 11:25:46
  • Android编程基于自定义View实现绚丽的圆形进度条功能示例

    2023-07-24 17:13:26
  • 深入了解Java核心类库--BigDecimal和System类

    2023-12-18 01:50:28
  • Spring如何处理注解的深入理解

    2023-09-09 14:35:49
  • Android Studio设置或修改Android SDK路径方法

    2023-11-07 17:22:10
  • C# 时间戳转换实例

    2022-12-07 12:17:57
  • 浅谈C#中简单的异常引发与处理操作

    2022-03-10 04:54:49
  • Springboot实现高吞吐量异步处理详解(适用于高并发场景)

    2023-08-20 23:40:35
  • C# Resources资源详解

    2021-10-13 02:49:32
  • C#实现将窗体固定在显示器的左上角且不能移动的方法

    2022-03-04 18:34:17
  • MVPXlistView展示上拉下拉效果

    2022-10-30 10:45:38
  • 浅谈Spring-cloud 之 sleuth 服务链路跟踪

    2022-09-24 16:07:43
  • 盘点几种常见的java排序算法

    2023-09-17 10:13:10
  • 详解如何使用maven生成可以执行的jar

    2023-08-17 00:18:43
  • spring定时任务执行两次及tomcat部署缓慢问题的解决方法

    2022-12-27 09:53:25
  • 浅谈HTTP使用BASIC认证的原理及实现方法

    2021-07-18 01:36:16
  • Android学习之AppWidget笔记分享

    2022-04-10 21:25:46
  • Mybatis如何传入多个参数的实现代码

    2022-02-26 02:52:24
  • Spark SQL 编程初级实践详解

    2022-06-13 18:37:56
  • springboot自定义starter方法及注解实例

    2022-11-02 10:52:08
  • asp之家 软件编程 m.aspxhome.com