最近工作需要在登录时使用滑动验证码做登录校验,在生成验证码图片的时候碰到了不小的麻烦 : (。

网上能查到的做法基本上都是使用一张已存在的实际图片作为滑块的图形模板,然后按照此模板做二重循环逐像素地从源图像抠出滑块以及新图。

这种方式优点就是可以控制每个像素,如改变局部的 Alpha 值、做局部的高斯模糊等。缺点也显而易见——太麻烦,且二重循环对内存也是不小的负担。

笔者的想法是:首先生成滑块 1)根据规定好的路径生成闭合区间;2)设置 Graphics2D 的渲染区间,限制仅渲染此闭合区间的内部(setClip方法);3)使用原图来渲染当前 Image(drawImage方法)。最后在源图扣掉滑块的地方加上阴影。

研究了一下 Java 的 awt 图像处理,这里对这几天的成果做一个记录,本文仅涉及图像处理方面,去掉了其它业务逻辑。

生成闭合区间

Java awt中提供了Shape接口,来代表任意一种几何图形。考虑我们要实现如下滑块图形:

上图左边的滑块可以先简化为右侧,原理是一样的。右边的图像一共有 A、B、C、D、E、F 六个顶点。其中 CD 之间是一段圆弧。Graphics2D的坐标系从左上角开始,X轴往下、Y轴往右是正方向。这里先算出各顶点坐标:A(0,0)、B(0,50)、C(15,50)、D(35,50)、E(50,50)、F(50,0)。

注意到H1'和H2'两个点。CD 间的圆弧由三阶贝塞尔曲线表示,H1' 和 H2' 就是此贝塞尔曲线的控制点,坐标为:H1'(15, 50+40/3),H2'(35, 50+40/3)。

下面先来看看绘制的形状是否正确(为了美观,X轴和Y轴都向正方向平移了30像素):

import javax.swing.*;

import java.awt.*;

import java.awt.geom.GeneralPath;

public class CreateSlideShape extends JComponent {

public void paint(Graphics g) {

Graphics2D g2d = (Graphics2D) g;

// 设置线条粗细

g2d.setStroke(new BasicStroke(3));

g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

GeneralPath path2D = new GeneralPath();

path2D.moveTo(offsetX, offsetY);

path2D.lineTo(offsetX, 50 + offsetY);

path2D.lineTo(15 + offsetX, 50 + offsetY);

float f = 13.333f;

path2D.curveTo(15 + offsetX, 50.f + f + offsetY, 35 + offsetX, 50.f + f + offsetY, 35 + offsetX, 50 + offsetY);

path2D.lineTo(50 + offsetX, 50 + offsetY);

path2D.lineTo(50 + offsetX, +offsetY);

path2D.closePath();

g2d.draw(path2D);

}

public static void main(String args[]) {

JFrame window = new JFrame();

window.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);

window.setBounds(30, 30, 150, 150);

window.getContentPane().add(new CreateSlideShape());

window.setVisible(true);

}

private static final int offsetX = 30;

private static final int offsetY = 30;

}

生成的图片如下:

滑块渲染 + 源图阴影

大体思路上边已经说过了,直接上代码。注意坐标系的变化:

import javax.imageio.ImageIO;

import java.awt.*;

import java.awt.geom.GeneralPath;

import java.awt.image.BufferedImage;

import java.awt.image.ColorModel;

import java.awt.image.WritableRaster;

import java.io.File;

import java.io.IOException;

/**

* 滑动验证码Demo

*

* @author Landas

*/

public class ImageClip {

/**

* 生成滑块,共分为两步:

* 1. 根据形状来绘制边框

* 2. 裁剪指定位置的源图到新的滑块图片

*

* @param sourceImage 源图片

* @param sliderShape 要生成的滑块图形

* @return 使用源图生成的滑块

*/

private static BufferedImage clip(BufferedImage sourceImage, Shape sliderShape) {

// 设置透明背景

ColorModel cm = ColorModel.getRGBdefault();

WritableRaster wr = cm.createCompatibleWritableRaster(slider_width, slider_height);

BufferedImage out = new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), null);

// 设置抗锯齿

Graphics2D g2d = out.createGraphics();

g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

// 绘制丑丑的边框当做阴影。实际使用时需要调整线宽以及颜色

g2d.setStroke(new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));

g2d.setColor(new Color(160, 160, 160));

g2d.draw(sliderShape);

// 调整当前 Graphics2D 的 context,使用 sliderShape 来限制渲染区域

g2d.setClip(sliderShape);

// 使用源图来渲染滑块,实际使用时注意坐标变换

g2d.drawImage(sourceImage, 0, 0, slider_width, slider_height, x, y, x + slider_width, y + slider_height, null);

// 绘制完毕,释放

g2d.dispose();

return out;

}

/**

* 源图裁剪掉滑块的部分需要加上阴影。

* 这里是简单粗暴的直接改变源图指定位置指定形状的 Alpha 值。实际使用中需要采用其他策略

*

* @param sourceImage 源图

* @param sliderShape 滑块形状

*/

private static void inverseClip(BufferedImage sourceImage, Shape sliderShape) {

Graphics2D g = sourceImage.createGraphics();

// 亮度简单设置为 50%

float percentage = .5f;

int brightness = (int) (256 - 256 * percentage);

g.setColor(new Color(0, 0, 0, brightness));

// 坐标重新定位

g.translate(x, y);

g.fill(sliderShape);

g.dispose();

}

// 生成滑块形状,请根据项目需要调整

private static Shape createShape() {

GeneralPath path2D = new GeneralPath();

path2D.moveTo(0, 0);

path2D.lineTo(0, 50);

path2D.lineTo(15, 50);

path2D.curveTo(15, 63.333f, 35, 63.333f, 35, 50);

path2D.lineTo(50, 50);

path2D.lineTo(50, 0);

path2D.closePath();

return path2D;

}

public static void main(String[] args) throws IOException {

// 读取源图

BufferedImage background = ImageIO.read(new File("D:/source.jpg"));

// 生成滑块的形状

Shape sliderShape = createShape();

// 生成滑块的图片并保存

BufferedImage sliderImage = clip(background, sliderShape);

File outputfile = new File("D:/slider.png");

ImageIO.write(sliderImage, "png", outputfile);

// 源图加上阴影并保存

inverseClip(background, sliderShape);

File outputfile2 = new File("D:/sourceCopy.png");

ImageIO.write(background, "png", outputfile2);

}

// 指定裁剪滑块的位置,项目中需要随机生成

private static final int x = 300;

private static final int y = 130;

// 滑块的高度和宽度,正方形边长 50,半圆半径 10,边框预留 2,一共是62。根据项目需要调整

private static final int slider_width = 62;

private static final int slider_height = 62;

}

有关绘图的代码就这么多,实际项目中其他细节已经略去。下面来看看效果,源图片是作者丑丑的鼠绘,^_^。

源图:

滑块:

抠掉滑块之后的背景图片:

Fin.~

下面列出参考文档:

java 滑块验证码 开源,Java AWT生成滑动验证码相关推荐

  1. 使用java + selenium + OpenCV破解网易易盾滑动验证码

    使用java + selenium + OpenCV破解网易易盾滑动验证码 网易易盾:dun.163.com * 验证码地址:https://dun.163.com/trial/jigsaw * 使用 ...

  2. java生成验证码工具类_Java生成图形验证码工具类

    生成验证码效果 validatecode.java 验证码生成类 package cn.dsna.util.images; import java.awt.color; import java.awt ...

  3. java 爬虫:开源java爬虫 swing工具 Imgraber

    1实现点: 1.返回给定URL网页内,所有图像url list 2.返回给定URL网页内,自动生成图像文件路径.txt 文件 3.返回给定URL网页内,下载txt文件指定的图片url,并将所有图像保存 ...

  4. 易语言 java支持_开源Java客户端可以连接易语言服务器

    我们的服务端处理客户端的连接请求是同步进行的, 每次接收到来自客户端的连接请求后, 都要先跟当前的客户端通信完之后才能再处理下一个连接请求. 这在并发比较多的情况下会严重影响程序的性能, 为此,我们可 ...

  5. python处理滑块验证码_使用python实现滑动验证码

    首先安装一个需要用到的模块 pip install social-auth-app-django 安装完后在终端输入pip list会看到 social-auth-app-django 3.1.0so ...

  6. python实现滑动验证码_使用python实现滑动验证码

    首先安装一个需要用到的模块 pip install social-auth-app-django 安装完后在终端输入pip list会看到 social-auth-app-django 3.1.0 s ...

  7. java 采集 cms_开源 java CMS - FreeCMS2.6 Web页面信息采集

    java开源论坛系统http://javabbs.javaz.cn Web页面信息采集 从FreeCMS 2.1开始支持 通过简单配置即可抓取目标网页信息,支持增量式采集.关键字替换.定时采集,同一采 ...

  8. java 采集 cms_开源 java CMS - FreeCMS2.6 数据库信息采集

    java开源论坛系统http://javabbs.javaz.cn 数据库信息采集 从FreeCMS 2.1开始支持 通过简单配置即可抓取目标数据库信息,支持增量式采集.关键字替换.定时采集,可采集多 ...

  9. java 采集 cms_开源 java CMS - FreeCMS2.3 Web页面信息采集

    Web页面信息采集 从FreeCMS 2.1开始支持 通过简单配置即可抓取目标网页信息,支持增量式采集.关键字替换.定时采集,同一采集规则可采集多个页面(静态和动态),可采集多种信息属性,可自动审核且 ...

最新文章

  1. 网络慢是带宽不足?优化网络带宽的5个小窍门
  2. Python3学习笔记01-环境安装和运行环境
  3. python3报错:importError: dynamic module does not define module export function (PyInit_cv_bridge_boost
  4. arduinopn532模块_树莓派使用libnfc驱动ITEAD NFC PN532模块
  5. CCF 2014-3-1 相反数
  6. node link 踩坑记录
  7. 这才是智能家居真正的现状
  8. 个人源码管理,SVN本地化
  9. 2021-08-06 MD5mysql 加密校验
  10. Shell_NotifyIcon
  11. 伍斯特理工学院计算机科学硕士,2020年伍斯特理工学院排名TFE Times美国最佳计算机科学硕士专业排名第100...
  12. 4.1%的利率,100万贷款,30年还款,我们每月能少还多少房贷呢
  13. MongoDB 特殊索引
  14. 不再盯着男性发烧友,小米手机要去“撩妹”?
  15. 【HCNP-OSPF】LSA
  16. Linux Shell 内建命令 : sh命令详解
  17. 【外文翻译】外国友人写得很不错的Java Lambda表达式入门教程,我终于翻译好给大家啦!!!...
  18. 【教育】这么多年的应试教育,成果几何?
  19. MacOS Dock栏 取消推出延时
  20. 基于 Python/Vue/D2 实现的CRM管理系统(客户管理,产品管理,商机管理,合同管理,客户公海,权限管理等业务模块)

热门文章

  1. 装饰工程预结算教程电子书_如何做好工程项目预、结算审核
  2. winform响应时间最长是多少分钟_漫威电影女性角色出场统计:谁出场时间最长?谁出场次数最多?...
  3. vue+openlayers实现行政边界、标注交互、效果弹窗
  4. 轻松玩转K60--飞思卡尔
  5. 22岁高中学历的我 如何做到CTO年薪50万
  6. FPGA基础自学流程
  7. 克莱因瓶四维空间猜想
  8. react 动态修改路由_升级到 React Router 4 并实现动态加载和模块热替换
  9. 习题4-5 换硬币 (20分) 将一笔零钱换成5分、2分和1分的硬币,要求每种硬币至少有一枚,有几种不同的换法?
  10. (附源码)springboot客户信息管理系统 毕业设计 281609