基于Java生成图片验证码的方法解析
作者:全村最野的狗 发布时间:2022-01-22 06:00:37
使用Java生成图片验证码完全解析
在 Java 中开发图片验证码功能,您可以使用 Java 图形处理库,比如 Java Advanced Imaging (JAI) 或者 Java2D,来生成图片并将文本写入图片。具体实现方法如下:
创建一个 BufferedImage 对象,并设置图片的宽度和高度。
获取图片的 Graphics2D 对象,并设置文本的颜色和字体。
在图片上绘制文本。
对图片进行一些随机处理,比如加入干扰线、噪点等,以增加图片验证码的难度。
将图片输出到浏览器,并设置相应的 Content-Type。或者将BufferedImage转为base64编码输出到浏览器。(本次统一输出到文件)
下面是一个简单的示例代码,可以帮助您快速开始:
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() 方法在图片上绘制噪点。
例如,下面的代码演示了如何在图片上随机绘制 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() 方法在图片上绘制干扰线。
例如,下面的代码演示了如何在图片上随机绘制 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 类可以生成矩形噪点。
下面是一个简单的示例代码,演示了如何使用图形生成算法生成噪点:
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() 方法来旋转文本。例如,下面的代码演示了如何在图片上斜放文本:
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() 方法将角度转换为弧度。
四位图形验证码
实现一个支持图形干扰算法,斜放文本,使用特殊的字体,动态文本的颜色的四位图形验证码
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() 方法来设置透明度。例如,下面的代码演示了如何调整噪点的透明度:
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


猜你喜欢
- Android 实现单线程轮循机制批量下载图片listview 在为item 添加从网上下载下来的图片时, 如果每次都整合一个item时都需
- 单例类保证一个类全局仅有一个实例,并提供一个全局访问点,由于只能生成一个实例,因此我们必须把构造函数设为私有函数以禁止他人创建实例。实现1:
- 在整合SpringBoot和Mybatis-plus时,想写自定义的sql,所以创建了Mapper.xml文件,但是启动后却老是报错:org
- Java Double相加出现的怪事问题的提出编译运行下面这个程序会看到什么public class test { public stati
- 平时在开发时经常会用到 const,readonly,static 关键字,可以肯定这些关键词是完全不同的概念,但有时候他们在用法上很相似以
- 1. 快速创建maven管理的SpringBoot项目1、访问 http://start.spring.io/2、 选择构建工具Maven
- 今天在用OpenCV实验Image Pyramid的时候发现一个奇怪的问题,就是利用C++函数imread读取图片的时候返回的结果总是空,而
- 本篇介绍了SpringBoot 缓存(EhCache 2.x 篇),分享给大家,具体如下:SpringBoot 缓存在 spring Boo
- java 中链表的定义与使用方法Java实现链表主要依靠引用传递,引用可以理解为地址,链表的遍历多使用递归,这里我存在一个疑问同一个类的不同
- 本文实例为大家分享了java实现银行管理系统的具体代码,供大家参考,具体内容如下Bank类package First;import java
- Looper是什么用于为线程运行消息循环的类。默认情况下,线程没有与之关联的消息循环。要创建一个,在要运行循环的线程中调用 prepare(
- 最近在定制Android系统音量条,发现代码还是蛮多的,下面总结一下。 代码是基于5.1.1版本的。 系统音量条的代码是在/framewor
- 本文实例讲述了C#异步调用的方法。分享给大家供大家参考。具体如下:using System;using System.Collections
- 简介JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation。在任何时候,当你要处理一个应用程序的业务逻
- 前言在阅读Kotlin的代码时,经常有看到 :: 这个符号,这个符号专业术语叫做成员引用,在代码中使用可以简化代码,那到底怎么使用呢以及使用
- 本文较为详细的描述了重载运算符的方法。一般来说,重载运算符在实际的项目开发中会经常的用到,但如果某些自定义类型通过简短几行代码重载一些常用的
- 推荐IntelliJ IDEA 2020.2.3永久破解激活教程(亲测有效)正文开始今天将idea更新到了最新版2020.2.3,结果发现新
- starter起步依赖starter起步依赖是springboot一种非常重要的机制,它打包了某些场景下需要用到依赖,将其统一集成到star
- 前言等待总是让人感到焦急和厌烦的,特别是看不到进展的等待。所以为了不让用户痴痴地等,我们在进行某些耗时操作时,一般都要设计一个进度条或者倒计
- JetpackJetpack,我觉得翻译为“飞行器”更好听,因为Google针对编程历史乱象,整理出