栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

JAVA 滑块拼图验证码

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

JAVA 滑块拼图验证码

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;


@Data
public class ImageDto {

    @ApiModelProperty(value = "图片的长")
    private Integer width;

    @ApiModelProperty(value = "图片的高")
    private Integer height;

    @ApiModelProperty(value = "图片信息")
    private String imagebase64;
}
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;


@Data
public class ImageVerifyDto {

    @ApiModelProperty(value = "大图信息")
    private ImageDto bigImage;

    @ApiModelProperty(value = "小图信息")
    private ImageDto smallImage;

    @ApiModelProperty(value = "小图y坐标")
    private Integer yHeight;

    @ApiModelProperty(value = "小图x坐标")
    private Integer xWidth;
}
package org.code.modules.system.util;

import lombok.extern.slf4j.Slf4j;
import org.code.modules.system.model.ImageDto;
import org.code.modules.system.model.ImageVerifyDto;
import org.springframework.util.base64Utils;
import sun.misc.base64Encoder;

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.Random;


@Slf4j
public class SlipImageUtil {

    private static int targetWidth = 180;//小图长(根据原图的大小设置滑动图片的长度)
    private static int targetHeight = 160;//小图宽(根据原图的大小设置滑动图片的高度)
    private static int circleR = 25;//半径(根据原图的大小设置滑半径的大小)
    private static int r1 = 20;//距离点(根据原图的大小设置距离点的大小)
    
    private static final String base64_PNG = "data:image/png;base64,";
    private static final String base64_JPG = "data:image/jpg;base64,";

    
    private static final String IMG_FORMAT_PNG = "png";
    private static final String IMG_FORMAT_JPG = "jpg";

    
    private static int[][] getBlockData() {
        int[][] data = new int[targetWidth][targetHeight];
        double x2 = targetWidth -circleR; //47

        //随机生成圆的位置
        double h1 = circleR + Math.random() * (targetWidth-3*circleR-r1);
        double po = Math.pow(circleR,2); //64

        double xbegin = targetWidth - circleR - r1;
        double ybegin = targetHeight- circleR - r1;

        //圆的标准方程 (x-a)²+(y-b)²=r²,标识圆心(a,b),半径为r的圆
        //计算需要的小图轮廓,用二维数组来表示,二维数组有两张值,0和1,其中0表示没有颜色,1有颜色
        for (int i = 0; i < targetWidth; i++) {
            for (int j = 0; j < targetHeight; j++) {
                double d2 = Math.pow(j - 2,2) + Math.pow(i - h1,2);
                double d3 = Math.pow(i - x2,2) + Math.pow(j - h1,2);
                if ((j <= ybegin && d2 < po)||(i >= xbegin && d3 > po)) {
                    data[i][j] = 0;
                }  else {
                    data[i][j] = 1;
                }
            }
        }
        return data;
    }

    
    private static void cutByTemplate(BufferedImage oriImage, BufferedImage targetImage, int[][] templateImage, int x, int y){
        int[][] martrix = new int[3][3];
        int[] values = new int[9];
        //创建shape区域
        for (int i = 0; i < targetWidth; i++) {
            for (int j = 0; j < targetHeight; j++) {
                int rgb = templateImage[i][j];
                // 原图中对应位置变色处理
                int rgb_ori = oriImage.getRGB(x + i, y + j);

                if (rgb == 1) {
                    targetImage.setRGB(i, j, rgb_ori);

                    //抠图区域高斯模糊
                    readPixel(oriImage, x + i, y + j, values);
                    fillMatrix(martrix, values);
                    oriImage.setRGB(x + i, y + j, avgMatrix(martrix));
                }else{
                    //这里把背景设为透明
                    targetImage.setRGB(i, j, rgb_ori & 0x00ffffff);
                }
            }
        }
    }


    private static void readPixel(BufferedImage img, int x, int y, int[] pixels) {
        int xStart = x - 1;
        int yStart = y - 1;
        int current = 0;
        for (int i = xStart; i < 3 + xStart; i++)
            for (int j = yStart; j < 3 + yStart; j++) {
                int tx = i;
                if (tx < 0) {
                    tx = -tx;

                } else if (tx >= img.getWidth()) {
                    tx = x;
                }
                int ty = j;
                if (ty < 0) {
                    ty = -ty;
                } else if (ty >= img.getHeight()) {
                    ty = y;
                }
                pixels[current++] = img.getRGB(tx, ty);

            }
    }

    private static void fillMatrix(int[][] matrix, int[] values) {
        int filled = 0;
        for (int i = 0; i < matrix.length; i++) {
            int[] x = matrix[i];
            for (int j = 0; j < x.length; j++) {
                x[j] = values[filled++];
            }
        }
    }

    private static int avgMatrix(int[][] matrix) {
        int r = 0;
        int g = 0;
        int b = 0;
        for (int i = 0; i < matrix.length; i++) {
            int[] x = matrix[i];
            for (int j = 0; j < x.length; j++) {
                if (j == 1) {
                    continue;
                }
                Color c = new Color(x[j]);
                r += c.getRed();
                g += c.getGreen();
                b += c.getBlue();
            }
        }
        return new Color(r / 8, g / 8, b / 8).getRGB();
    }

    
    public static ImageVerifyDto createImage(File file){

        ImageVerifyDto returnDto = new ImageVerifyDto();
        ImageDto bigImage = new ImageDto();
        ImageDto smallImage = new ImageDto();
        try {
            BufferedImage bigBufferedImage = ImageIO.read(file);
            Random random = new Random();
            //X轴距离右端targetWidth  Y轴距离底部targetHeight以上
            int widthRandom = random.nextInt(bigBufferedImage.getWidth()-  2*targetWidth) + targetWidth;
            int heightRandom = random.nextInt(bigBufferedImage.getHeight()- targetHeight);
            log.info("原图大小{} x {},随机生成的坐标 X,Y 为({},{})",bigBufferedImage.getWidth(),bigBufferedImage.getHeight(),widthRandom,heightRandom);

            BufferedImage smallBufferedImage= new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_4BYTE_ABGR);
            cutByTemplate(bigBufferedImage,smallBufferedImage,getBlockData(),widthRandom,heightRandom);

            bigImage.setWidth(bigBufferedImage.getWidth());//大图的宽
            bigImage.setHeight(bigBufferedImage.getHeight());//大图的高
            bigImage.setImagebase64(base64_JPG+ getImageTobase64(bigBufferedImage,IMG_FORMAT_JPG));//大图
            returnDto.setBigImage(bigImage);

            smallImage.setWidth(smallBufferedImage.getWidth());//小图的宽
            smallImage.setHeight(smallBufferedImage.getHeight());//小图的高
            smallImage.setImagebase64(base64_PNG+ getImageTobase64(smallBufferedImage,IMG_FORMAT_PNG));//小图,小图要转PNG背景色才不会变黑
            returnDto.setSmallImage(smallImage);

            returnDto.setXWidth(widthRandom);//小图x坐标
            returnDto.setYHeight(heightRandom);//小图y坐标

        } catch (Exception e) {
            log.error("创建图形验证码异常",e);
        } finally{
            return returnDto;
        }
    }


    
    public static ImageVerifyDto createImage(String imgUrl){

        ImageVerifyDto returnDto = new ImageVerifyDto();
        ImageDto bigImage = new ImageDto();
        ImageDto smallImage = new ImageDto();

        try {
            //通过URL 读取图片
            URL url = new URL(imgUrl);
            BufferedImage bigBufferedImage = ImageIO.read(url.openStream());
            Random rand = new Random();
            int widthRandom = rand.nextInt(bigBufferedImage.getWidth()-  targetWidth - 100 + 1 ) + 100;
            int heightRandom = rand.nextInt(bigBufferedImage.getHeight()- targetHeight + 1 );
            log.info("原图大小{} x {},随机生成的坐标 X,Y 为({},{})",bigBufferedImage.getWidth(),bigBufferedImage.getHeight(),widthRandom,heightRandom);

            BufferedImage smallBufferedImage= new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_4BYTE_ABGR);
            cutByTemplate(bigBufferedImage,smallBufferedImage,getBlockData(),widthRandom,heightRandom);

            bigImage.setWidth(bigBufferedImage.getWidth());//大图的宽
            bigImage.setHeight(bigBufferedImage.getHeight());//大图的高
            bigImage.setImagebase64(base64_JPG+ getImageTobase64(bigBufferedImage,IMG_FORMAT_JPG));//大图
            returnDto.setBigImage(bigImage);

            smallImage.setWidth(smallBufferedImage.getWidth());//小图的宽
            smallImage.setHeight(smallBufferedImage.getHeight());//小图的高
            smallImage.setImagebase64(base64_PNG+ getImageTobase64(smallBufferedImage,IMG_FORMAT_PNG));//小图,小图要转PNG背景色才不会变黑
            returnDto.setSmallImage(smallImage);

            returnDto.setXWidth(widthRandom);//小图x坐标
            returnDto.setYHeight(heightRandom);//小图y坐标

        } catch (Exception e) {
            log.error("创建图形验证码异常",e);
        } finally{
            return returnDto;
        }
    }


    
    public static String getImagebase64(BufferedImage image) throws IOException {
        byte[] imagedata = null;
        ByteArrayOutputStream bao=new ByteArrayOutputStream();
        ImageIO.write(image,IMG_FORMAT_PNG,bao);
        imagedata=bao.toByteArray();
        base64Encoder encoder = new base64Encoder();
        String base64IMAGE=encoder.encodeBuffer(imagedata).trim();
        base64IMAGE = base64IMAGE.replaceAll("r|n", "");  //删除 rn
        return base64IMAGE;
    }

    
    public static String getImageTobase64(BufferedImage image, String imageType) throws IOException {
        ByteArrayOutputStream byteBigStream = new ByteArrayOutputStream();
        //写入流中
        ImageIO.write(image, imageType, byteBigStream);
        byte[] bytes_big = byteBigStream.toByteArray();
        return base64Utils.encodeToString(bytes_big);
    }

    public static void main(String[] args) {

        ImageVerifyDto dto = SlipImageUtil.createImage("http://xxxx/1.jpg");//图片地址,原图大小800*500
        System.out.println("bigImage:n"+dto.getBigImage().getImagebase64());
        System.out.println("smallImage:n"+dto.getSmallImage().getImagebase64());
    }

}
    @ApiOperation(value = "获取图形验证码")
    @RequestMapping(value = "/getImageVerify/{checkKey}", method = RequestMethod.GET)
    @ResponseBody
    public Result getImageVerifyCode(@PathVariable String checkKey) {

        String imageUrl = "http://xxxx/1.jpg";
        //读取网络图片
        ImageVerifyDto imageVerifyDto = SlipImageUtil.createImage(imageUrl);
        //验证码2分钟内有效
        redisUtil.set("imageCode:" + checkKey, imageVerifyDto.getXWidth(), 120);
        imageVerifyDto.setXWidth(null);

        return Result.ok(imageVerifyDto);
    }
    //moveLength:拖动的距离
    @ApiOperation(value = "验证图形验证码")
    @RequestMapping(value = "/checkImageVerifyCode", method = RequestMethod.GET)
    @ResponseBody
    public Result checkImageVerifyCode(@RequestParam(value = "moveLength", required = true) Double moveLength,
                                          @RequestParam(value = "checkKey", required = true) String checkKey) {

        if (null == moveLength) {
            return Result.error("验证失败");
        }
        Object obj = redisUtil.get("imageCode:" + checkKey);
        if(null == obj){
            return Result.error("验证过期,请重试");
        }
        Integer xWidth = (Integer) obj;
        if (Math.abs(xWidth - moveLength) > 10) {
            return Result.error("验证不通过");
        } else {
            redisUtil.del("imageCode:" + checkKey);
            return Result.ok("验证通过");
        }
    }

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/424332.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号