思路:

  1. 获得一张原图(originImage)和一张抠图模板(templateImage)
  2. 复制原图得到带alpha通道的原图的复制(shadowImage)
  3. 将原图的复制图先全部设置为不透明
  4. 将模板图(templateImage)所有不透明的像素的位置的滑块图(blockImage)替换成原图(originImage)的相应位置的像素
  5. 将原图的复制图(shadowImage)的抠图位置像素设置半透明
  6. 大功告成,返回原图的复制图(shadowImage)和滑块图(blockImage)

工具类

package com.sxapp.message.utils;import net.coobird.thumbnailator.Thumbnails;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;/*** @author Dirk* @Description 滑动验证码工具类* @Date Create at 2019-06-26 11:20*/
public class CaptchaUtil {private static final Logger log = LoggerFactory.getLogger(CaptchaUtil.class);/*** @param originImage   原图* @param templateImage 抠图模板* @param x             原图上的抠图位置* @param y             原图上的抠图位置* @return 滑动小方块图和带阴影的原图*/public static Map<String, String> getCaptchaImages(BufferedImage originImage, BufferedImage templateImage,int x, int y) {// 滑动小方块图BufferedImage blockImage = new BufferedImage(templateImage.getWidth(), templateImage.getHeight(),templateImage.getType());// 带alpha通道的原图的复制 --> 带阴影的原图BufferedImage shadowImage = new BufferedImage(originImage.getWidth(), originImage.getHeight(),BufferedImage.TYPE_4BYTE_ABGR);// 原图像矩阵int[][] originImageData = getData(originImage);// 模板图像矩阵int[][] templateImageData = getData(templateImage);// shadowImage 设置不透明for (int i = 0; i < originImageData.length; i++) {for (int j = 0; j < originImageData[i].length; j++) {int color = originImage.getRGB(i, j);final int r = (color >> 16) & 0xff;final int g = (color >> 8) & 0xff;final int b = color & 0xff;shadowImage.setRGB(i, j, colorToRGB(255, r, g, b));}}// 抠图for (int i = 0; i < templateImageData.length; i++) {for (int j = 0; j < templateImageData[i].length; j++) {int alpha = (templateImageData[i][j] >> 24) & 0xff;if (alpha > 128) {// 复制原图抠图区域到滑动小方块int color = originImageData[x + i][y + j];blockImage.setRGB(i, j, color);// shadowImage 抠图区域加权法灰度化并设置半透明final int r = (color >> 16) & 0xff;final int g = (color >> 8) & 0xff;final int b = color & 0xff;int gray = (int) (0.3 * r + 0.59 * g + 0.11 * b);shadowImage.setRGB(x + i, y + j, colorToRGB(150, gray, gray, gray));} else if (alpha > 0) {// 将templateImage的描边复制给blockImageint color = templateImageData[i][j];final int r = getRed(color);final int g = getGreen(color);final int b = getBlue(color);blockImage.setRGB(i, j, colorToRGB(alpha, r, g, b));}}}// 图片处理:png转jpg,高斯模糊,图片压缩shadowImage = imageCompression(blur(png2jpg(shadowImage)), 0.5, 1);blockImage = imageCompression(blockImage, 0.5, 1);//返回扣出的小方块图和带阴影的原图Map<String, String> result = new HashMap<>(2);result.put("blockImage", imageToBase64(blockImage, "png"));result.put("shadowImage", imageToBase64(shadowImage, "jpg"));return result;}/*** @param bufferedImage 源图片* @param size          压缩尺寸比例,取值0 ~ 1,1 表示原图大小* @param quality       压缩质量比例,取值 0 ~ 1,1 表示原图质量* @return*/private static BufferedImage imageCompression(BufferedImage bufferedImage, double size, double quality) {try {return Thumbnails.of(bufferedImage).scale(size).outputQuality(quality).asBufferedImage();} catch (IOException e) {log.error("图片压缩失败:【{}】", e.getMessage());e.printStackTrace();}return bufferedImage;}private static BufferedImage png2jpg(BufferedImage png) {BufferedImage jpg = new BufferedImage(png.getWidth(), png.getHeight(), BufferedImage.TYPE_INT_RGB);jpg.createGraphics().drawImage(png, 0, 0, Color.BLACK, null);return jpg;}/*** 生成图像矩阵** @param bufferedImage 图片* @return 像素信息的二维数组*/private static int[][] getData(BufferedImage bufferedImage) {int[][] data = new int[bufferedImage.getWidth()][bufferedImage.getHeight()];for (int i = 0; i < bufferedImage.getWidth(); i++) {for (int j = 0; j < bufferedImage.getHeight(); j++) {data[i][j] = bufferedImage.getRGB(i, j);}}return data;}private static int getAlpha(int color) {return (color >> 24) & 0xff;}private static int getRed(int color) {return (color >> 16) & 0xff;}private static int getGreen(int color) {return (color >> 8) & 0xff;}private static int getBlue(int color) {return color & 0xff;}/*** 颜色分量转换为RGB值** @param alpha* @param red* @param green* @param blue* @return*/private static int colorToRGB(int alpha, int red, int green, int blue) {int newPixel = 0;newPixel += alpha;newPixel = newPixel << 8;newPixel += red;newPixel = newPixel << 8;newPixel += green;newPixel = newPixel << 8;newPixel += blue;return newPixel;}/*** base64字符串和图片互转** @param image      图片* @param formatName 图片格式* @return base64字符串*/private static String imageToBase64(BufferedImage image, String formatName) {ByteArrayOutputStream os = new ByteArrayOutputStream();try {ImageIO.write(image, formatName, os);} catch (IOException e) {e.printStackTrace();}byte[] imageData = os.toByteArray();String base64Image = "data:image/jpg;base64,";base64Image = base64Image.concat(java.util.Base64.getEncoder().encodeToString(imageData));base64Image = base64Image.replaceAll("\n", "").replaceAll("\r", "");return base64Image;}/*** base64字符串和图片互转** @param base64String base64字符串* @return 图片*/public static BufferedImage base64StringToImage(String base64String) {try {byte[] imageData = Base64.getDecoder().decode(base64String);ByteArrayInputStream is = new ByteArrayInputStream(imageData);return ImageIO.read(is);} catch (IOException e) {e.printStackTrace();}return null;}/*** 获得抠图位置** @param origin   原图的长宽* @param template 抠图模板图的长宽* @return 随机抠图位置*/public static int getPosition(Integer origin, Integer template) {int difference = origin - template;if (difference <= 0) {return 0;}int position = new Random().nextInt(difference);if (position < origin / 2 && position + origin / 2 + template < origin) {position += origin / 2;}return position;}/*** 生成验证码** @param length 验证码长度* @return 验证码*/public static String generateCaptcha(Integer length) {StringBuilder captcha = new StringBuilder();Random random = new Random();for (int i = 0; i < length; i++) {captcha.append(random.nextInt(10));}return captcha.toString();}/*** 高斯模糊** @param originImage 原图* @return 修改后的图*/private static BufferedImage blur(BufferedImage originImage) {BufferedImage newImage = new BufferedImage(originImage.getWidth(), originImage.getHeight(),originImage.getType());int[][] data = getData(originImage);int width = originImage.getWidth();int height = originImage.getHeight();for (int i = 0; i < width; i++) {for (int j = 0; j < height; j++) {if (i == 0 || j == 0 || i == width - 1 || j == height - 1) {newImage.setRGB(i, j, originImage.getRGB(i, j));continue;}// 获得原图该点为中心的九宫矩阵int[][] color = new int[][]{{data[i - 1][j - 1], data[i - 1][j], data[i - 1][j + 1]},{data[i][j - 1], data[i][j], data[i][j + 1]},{data[i + 1][j - 1], data[i + 1][j], data[i + 1][j + 1]}};newImage.setRGB(i, j, gaussianBlur(color));}}return newImage;}/*** 通过该点的九宫矩阵像素计算得到经过高斯模糊后该像素的颜色** @param color 二维3*3数组* @return*/private static int gaussianBlur(int[][] color) {float[][] template = new float[][]{{0.0947416f, 0.118318f, 0.0947416f}, {0.118318f, 0.147761f, 0.118318f},{0.0947416f, 0.118318f, 0.0947416f}};float alpha = 0f;float r = 0f;float g = 0f;float b = 0f;for (int i = 0; i < template.length; i++) {for (int j = 0; j < template[i].length; j++) {alpha += template[i][j] * getAlpha(color[i][j]);r += template[i][j] * getRed(color[i][j]);g += template[i][j] * getGreen(color[i][j]);b += template[i][j] * getBlue(color[i][j]);}}return colorToRGB(Math.round(alpha), Math.round(r), Math.round(g), Math.round(b));}
}

服务调用

     Random random = new Random();int targetNo = random.nextInt(Integer.parseInt(targetCount)) + 1;int templateNo = random.nextInt(Integer.parseInt(templateCount)) + 1;log.debug("targetNo: [{}] templateNo: [{}]", targetNo, templateNo);BufferedImage oriImage;BufferedImage templateImage;Map<String, String> resultMap;int x, y;try {// 读取原图和模板图 根据具体路径设置oriImage = ImageIO.read(Objects.requireNonNull(getClass().getClassLoader().getResourceAsStream("static/targets/" + targetNo + ".jpg")));templateImage = ImageIO.read(Objects.requireNonNull(getClass().getClassLoader().getResourceAsStream("static/templates/" + templateNo + ".png")));// 生成抠图位置x = CaptchaUtil.getPosition(oriImage.getWidth(), templateImage.getWidth());y = CaptchaUtil.getPosition(oriImage.getHeight(), templateImage.getHeight());// 获取滑动小块图像和带阴影原图resultMap = CaptchaUtil.getCaptchaImages(oriImage, templateImage, x, y);} catch (IOException e) {e.printStackTrace();}resultMap.put("Y", String.valueOf((int) ((float) y / (float) oriImage.getHeight() * 100)));return resultMap;

抠图模板:

模板说明:

  • 背景部分不透明度为0
  • 黑色边框为不透明度小于等于50%
  • 中间图案部分不透明度大于50%

生成图片滑动验证码图片相关推荐

  1. java 解析滑动验证码图片_滑动图片验证码demo

    [实例简介] 极验验证更改后的版本,该demo导入eclipse直接可用,带有详细使用说明文档,验证通过发送短信 [实例截图] [核心代码] 极验验证使用说明 └── 极验验证使用说明 ├── gt- ...

  2. java验证码图片滑动验证码_图片滑动验证码的生成

    使用Java生成图片滑动验证码 image.png 目前接到了一个新的小需求,要在登录时进行滑动图片验证. 搜了一下网上的demo,没有太多很完整的demo.就参考各种文档自己拼凑了一个出来.整理一下 ...

  3. 【Lilishop商城】No3-2.模块详细设计,系统设置(系统配置、行政区划、物流公司、滑块验证码图片、敏感词过滤)的详细设计

     仅涉及后端,全部目录看顶部专栏,代码.文档.接口路径在: [Lilishop商城]记录一下B2B2C商城系统学习笔记~_清晨敲代码的博客-CSDN博客 全篇会结合业务介绍重点设计逻辑,其中重点包括接 ...

  4. 对极验geetest滑块验证码图片还原算法的研究

    免责声明 本文章所提到的技术仅用于学习用途,禁止使用本文章的任何技术进行发起网络攻击.非法利用等网络犯罪行为,一切信息禁止用于任何非法用途.若读者利用文章所提到的技术实施违法犯罪行为,其责任一概由读者 ...

  5. 如何破解滑动验证码?

    本文通过自动化查询域名或公司的备案信息,来演示其中图片滑动验证码的破解方式,以此来思考验证码的安全性问题,思考如何设计出安全性更高的验证码. 注意:破解验证码进行网络内容抓取可能是一种违规行为,可以以 ...

  6. 如何破解极验滑动验证码?成功率 100%!

    注:已对文章中所涉及的敏感内容,如图片/文字/URL 进行脱敏处理. 什么是"极验"? 或许你没听说过极验[1],但你很大可能使用过极验的产品.极验是首家「行为式验证」安全技术服务 ...

  7. html 图片滑动验证码,selenium滑动验证码

    selenium验证滑条验证码时一直提示请重新滑动. python+selenium中验证码怎么定位 selenium验证码怎么进行自动化测试 selenium+python怎么模拟用户输入验证码登录 ...

  8. 一步步实现滑动验证码(拼图验证码),Java图片处理关键代码

    最近滑动验证码在很多网站逐步流行起来,一方面对用户体验来说,比较新颖,操作简单,另一方面相对图形验证码来说,安全性并没有很大的降低.当然到目前为止,没有绝对的安全验证,只是不断增加攻击者的绕过成本. ...

  9. springmvc使用谷歌captcha生成图片验证码,并将验证码图片以二进制流的方式返回给前端(app和pc端都能调用)

    近期对登录注册与获取短信验证码的接口做了安全限制,其中一部分就用到了谷歌的captcha验证码,比如当用户连续三次登陆失败,那么之后的登录请求就需要用户输入谷歌的图形验证码.由于web端和app端调用 ...

最新文章

  1. bat 批处理切换到当前脚本所在文件夹
  2. operator、explicit与implicit
  3. 安卓游戏开发推箱子_保持冷静并砍箱子-开发
  4. Kubeflow使用Kubernetes进行机器学习GPU分布式训练
  5. nginx ---- Nginx服务器基础配置实例
  6. Android大学课件SQLite3 数据库操作
  7. Linux操作Oracle(12)——Oracle创建只读账号 【手把手教程】
  8. MemCache详细解读(转)
  9. tcp/ip IP数据报头详解
  10. linux下usb无线网卡对比
  11. 纯HTML+js实现鼠标滚轮动态调整缩放图片大小
  12. 计算机启动 滴的一声,电脑开机没反应 电脑开机没有滴的一声
  13. curl php 模拟来源_php采用curl实现伪造IP来源的方法
  14. BTrace-Java 线上问题排查神器
  15. 单独上线音乐直播APP,“LOOK直播”能给网易云音乐带来什么?
  16. 解决Required XXX parameter ‘XXX‘ is not present问题
  17. 876计算机大纲,876水力学考大纲.doc
  18. ffmpeg无损 mts转mp4
  19. 码云上传本地文件夹,码云只能上传20个文件的突破方法
  20. Oracle 分析函数 over 和MySQL 实现类似效果写法

热门文章

  1. iS-RPA2022.1.0 | 艺赛旗RPA新版本正式发布
  2. Vue Uncaught SyntaxError: Unexpected token ‘<‘ 路由问题
  3. 数据库中的数据完整性约束
  4. css js html 实现滚动字幕
  5. 解决“javac不是内部或外部命令,也不是可运行的程序”问题
  6. 安卓系统源码编译系列(一)——下载安卓系统源码教程
  7. 程序员数学(9)--不等式与不等式组
  8. MTL831C MTL838C MTL5053 EATON传输模块
  9. 医疗行业大数据医疗分析案例
  10. 网页链接只能在微信端打开