java后端实现滑块拼图验证

编程入门 行业动态 更新时间:2024-10-28 14:22:24

java后端实现滑块<a href=https://www.elefans.com/category/jswz/34/1763369.html style=拼图验证"/>

java后端实现滑块拼图验证

1.直接上代码,首先创建一个PuzzleHelper 拼图助手方便生成滑块
说明:
1.滑块的背景图在资源库中的图片随机。
2.滑块的边缘凹凸随机。
3.滑块的位置随机。
你可能会出现的问题:
1.图片转BASE64我用的工具类,你需要自己去网上找一个。
2.你可能报错Can’t read input file!,是因为图片的地址不正确,所以找不到图片。

import com.ruoyimon.utils.sign.Base64;
import com.ruoyi.model.PuzzleInfo;
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.io.InputStream;
import java.util.Random;public class PuzzleHelper {//大图宽度private static final Integer bigWidth = 4000;//大图高度private static final Integer bigHeight = 2000;//边距(上、右、下小图距离大图最近距离,左边需要留大点边距方便拖动),同时也是内凹点和外凸点到正方形的边距private static final Integer margin = 100;//小正方形边长,制作拼图的轮廓private static final Integer square = 400;//小圆半径,拼图的凹凸轮廓private static final Integer circle = 80;//阴影宽度private static final Integer shadow=10;//图片压缩倍数private static final Integer scale=10;/*** @Title: getImageBASE64* @Description: 图片转BASE64*/public static String getImageBASE64(BufferedImage image) throws IOException {byte[] imagedata = null;ByteArrayOutputStream bao=new ByteArrayOutputStream();ImageIO.write(image,"png",bao);imagedata=bao.toByteArray();String BASE64IMAGE = Base64.encode(imagedata).trim();BASE64IMAGE = BASE64IMAGE.replaceAll("\r|\n", "");  //删除 \r\nreturn BASE64IMAGE;}/*** 改变图片大小** @param image  原图* @param width  目标宽度* @param height 目标高度* @return 目标图*/public static BufferedImage resizeImage(final Image image, int width, int height,boolean type) {BufferedImage bufferedImage;if (type){bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);}else {bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);}final Graphics2D graphics2D = bufferedImage.createGraphics();graphics2D.setComposite(AlphaComposite.Src);//below three lines are for RenderingHints for better image quality at cost of higher processing timegraphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);graphics2D.drawImage(image, 0, 0, width, height, null);graphics2D.dispose();return bufferedImage;}/*** 随机正方形坐标和边缘凹凸信息*/public static Integer[] getPosAndOutline(){//前端将图约束在300*150的框内,所以计算时除以10防止坐标约束时(除以10)出现小数//最小高度,只需排除边距加外凸Integer minY = (2*margin)/10;//最大高度,排除边距,正方形边长,上下两个外凸(极限)情况下,增加的高度。Integer maxY = (bigHeight - (square + 3 * margin))/10;//最小宽度,左边留一个半身位方便移动,身位宽度仍是极限(正方形边长+左右两个外凸)Integer minX = ((square + margin * 2) * 3 / 2)/10;//最大宽度,排除边距,正方形边长,左右两个外凸。Integer maxX = (bigWidth - (square + 3 * margin))/10;//获取正方形的位置,乘以10计算时保持正常大小,传给前端时需约束处理(除以10)Integer y = (minY + (int) (Math.random() * (maxY + 1 - minY)))*10;Integer x = (minX + (int) (Math.random() * (maxX + 1 - minX)))*10;Integer[] p=new Integer[10];//正方形x坐标p[0]=x;//正方形y坐标p[1]=y;//获取边缘凹凸信息//0没有 1内凹圆弧 2外凸圆弧Integer top = new Random().nextInt(3);Integer left = new Random().nextInt(3);Integer down = new Random().nextInt(3);Integer right = new Random().nextInt(3);//上方凹凸信息p[2]=top;//左侧凹凸信息p[3]=left;//下方凹凸信息p[4]=down;//右侧凹凸信息p[5]=right;return p;}/*** 获取小图轮廓位置信息,值为1的地方是小图需要从原图取色,大图需要在原图基础上模糊的位置*/public static Integer[][] getSmallImg(Integer[] pos) {//正方形x坐标Integer x=pos[0];//正方形y坐标Integer y=pos[1];//小图x坐标(小图没有左侧外凸时x坐标与正方形一致)Integer posX=null==pos[8]?pos[0]:pos[8];//小图y坐标(小图没有上方外凸时y坐标与正方形一致)Integer posY=null==pos[9]?pos[1]:pos[9];//0没有 1内凹圆弧 2外凸圆弧Integer top =  pos[2];Integer left =pos[3];Integer down = pos[4];Integer right = pos[5];//取色模板,值为1的地方是小图需要从原图取色,大图需要在原图基础上模糊的位置Integer[][] templateImage = new Integer[bigHeight][bigWidth];double rPow = Math.pow(circle, 2);//模板只需要计算小图范围,其他地方不用管,阴影范围需要从小图边界向外延申shadow长度作为参照for (int i = posY-shadow; i <= posY+pos[7]+shadow; i++) {for (int j = posX-shadow; j <= posX+pos[6]+shadow; j++) {//先判断正方形if ((i >= y && i <= (y + square) && j >= x && j <= (x + square))) {templateImage[i][j] = 1;} else {templateImage[i][j] = 0;}//不在上方圆内if (top == 1) {Integer tx = x + square / 2;Integer ty = y + (margin - circle);//当前点在上方圆形的位置内外double res = Math.pow(j - tx, 2) + Math.pow(i - ty, 2);//在圆内挖掉if (res <= rPow) {templateImage[i][j] = 0;}}//在上方圆内if (top == 2) {Integer tx = x + square / 2;Integer ty = y - (margin - circle);//当前点在上方圆形的位置内外double res = Math.pow(j - tx, 2) + Math.pow(i - ty, 2);//在圆内补上if (res <= rPow) {templateImage[i][j] = 1;}}//不在左侧圆内if (left == 1) {Integer tx = x + (margin - circle);Integer ty = y + square / 2;//当前点在左侧圆形的位置内外double res = Math.pow(j - tx, 2) + Math.pow(i - ty, 2);//在圆内挖掉if (res <= rPow) {templateImage[i][j] = 0;}}//在左侧圆内if (left == 2) {Integer tx = x - (margin - circle);Integer ty = y + square / 2;//当前点在左侧圆形的位置内外double res = Math.pow(j - tx, 2) + Math.pow(i - ty, 2);//在圆内挖掉if (res <= rPow) {templateImage[i][j] = 1;}}//不在下方圆内if (down == 1) {Integer tx = x + square / 2;Integer ty = y + square - (margin - circle);//当前点在左侧圆形的位置内外double res = Math.pow(j - tx, 2) + Math.pow(i - ty, 2);//在圆内挖掉if (res <= rPow) {templateImage[i][j] = 0;}}//在下方圆内if (down == 2) {Integer tx = x + square / 2;Integer ty = y + square + (margin - circle);//当前点在左侧圆形的位置内外double res = Math.pow(j - tx, 2) + Math.pow(i - ty, 2);//在圆内挖掉if (res <= rPow) {templateImage[i][j] = 1;}}//不在右侧圆内if (right == 1) {Integer tx = x + square - (margin - circle);Integer ty = y + square / 2;//当前点在左侧圆形的位置内外double res = Math.pow(j - tx, 2) + Math.pow(i - ty, 2);//在圆内挖掉if (res <= rPow) {templateImage[i][j] = 0;}}//在右侧圆内if (right == 2) {Integer tx = x + square + (margin - circle);Integer ty = y + square / 2;//当前点在左侧圆形的位置内外double res = Math.pow(j - tx, 2) + Math.pow(i - ty, 2);//在圆内挖掉if (res <= rPow) {templateImage[i][j] = 1;}}}}return templateImage;}/*** 从原图中裁剪拼图* @param oriImage* @param targetImage* @param templateImage* @param pos*/private static void cutByTemplate(BufferedImage oriImage, BufferedImage targetImage, Integer[][] templateImage,Integer[] pos) {int[][] martrix = new int[3][3];int[] values = new int[9];//小图x坐标(小图没有左侧外凸时x坐标与正方形一致)Integer posX=null==pos[8]?pos[0]:pos[8];Integer posY=null==pos[9]?pos[1]:pos[9];//创建shape区域for (int i = posY; i <=posY+pos[7]; i++) {for (int j = posX; j <= posX+pos[6]; j++) {int rgb = templateImage[i][j];// 原图中对应位置变色处理int rgb_ori = oriImage.getRGB(j, i);int top=1;int left=1;int down=1;int right=1;if (i>shadow-1){top= templateImage[i-shadow][j];}if (j>shadow-1){left = templateImage[i][j-shadow];}if (i<bigHeight-shadow){down = templateImage[i+shadow][j];}if (j<bigWidth-shadow){right = templateImage[i][j+shadow];}if (rgb == 1) {targetImage.setRGB(j-posX, i-posY, rgb_ori);//抠图区域高斯模糊readPixel(oriImage,  j, i, values);fillMatrix(martrix, values);oriImage.setRGB(j, i, avgMatrix(martrix));Color white = new Color(230,230,230);Color gray=new Color(40,40,40);Color black=new Color(20,20,20);//上方是图区外,当前为顶部边界,加重阴暗if (top==0){oriImage.setRGB(j, i,black.getRGB());targetImage.setRGB(j-posX, i-posY,white.getRGB());}//左侧是图区外,当前为左侧边界,加重阴暗if (left==0){oriImage.setRGB(j, i,black.getRGB());targetImage.setRGB(j-posX, i-posY,white.getRGB());}//下方是图区外,当前为下方边界,加重光亮if (down==0){oriImage.setRGB(j, i,white.getRGB());targetImage.setRGB(j-posX, i-posY,white.getRGB());}//右侧是图区外,当前为右侧边界,加重光亮if (right==0){oriImage.setRGB(j, i,white.getRGB());targetImage.setRGB(j-posX, i-posY,white.getRGB());}}
//                else {
//                    //这里把背景设为透明
//                    targetImage.setRGB(j, i, 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 PuzzleInfo getPuzzleInfo() throws IOException {//随机背景图int i = new Random().nextInt(10);String path ="puzzle/source"+i+".jpg";//拼图原图
//        ClassPathResource classPathResource = new ClassPathResource(path);InputStream inputStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(path);//        Image bi = ImageIO.read(classPathResource.getFile());Image bi = ImageIO.read(inputStream);//规范原图的大小BufferedImage oriImage=resizeImage(bi,bigWidth,bigHeight,true);//获取正方形的位置和边缘凹凸信息Integer[] pos = getPosAndOutline();//计算拼图的真实大小和拼图的位置信息Integer width=square+1;Integer height =square+1;if (pos[2]==2){//上方突出,真实高度加一个margin,真实坐标,正方形y坐标减去一个marginheight+=margin;pos[9]=pos[1]-margin;}if (pos[3]==2){width+=margin;pos[8]=pos[0]-margin;}if (pos[4]==2){height+=margin;}if (pos[5]==2){width+=margin;}pos[6]=width;pos[7]=height;//创建拼图BufferedImage targetImage= new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);//获取拼图的裁剪信息(0不要1裁剪)Integer[][] templateImage = getSmallImg(pos);//裁剪拼图cutByTemplate(oriImage,targetImage,templateImage,pos);PuzzleInfo puzzleInfo=new PuzzleInfo();
//        puzzleInfo.setBigImg(getImageBASE64(oriImage));
//        puzzleInfo.setSmallImg(getImageBASE64(targetImage));puzzleInfo.setBigImg(getImageBASE64(resizeImage(oriImage,bigWidth/scale,bigHeight/scale,true)));puzzleInfo.setSmallImg(getImageBASE64(resizeImage(targetImage,width/scale,height/scale,false)));puzzleInfo.setPosX(pos[8]==null?pos[0]/10:pos[8]/10);puzzleInfo.setPosY(pos[9]==null?pos[1]/10:pos[9]/10);puzzleInfo.setSmallWidth(width/10);puzzleInfo.setSmallHeight(height/10);puzzleInfo.setBigWidth(bigWidth/10);puzzleInfo.setBigHeight(bigHeight/10);return puzzleInfo;}public static void main(String[] args) throws IOException {File file1=new File("E:/img/small.png");File file2=new File("E:/img/big.jpg");File file= new File("E:/img/source.jpg");Image bi = ImageIO.read(file);BufferedImage oriImage=resizeImage(bi,bigWidth,bigHeight,true);Integer[] pos = getPosAndOutline();Integer width=square+1;Integer height =square+1;if (pos[2]==2){height+=margin;pos[9]=pos[1]-margin;}if (pos[3]==2){width+=margin;pos[8]=pos[0]-margin;}if (pos[4]==2){height+=margin;}if (pos[5]==2){width+=margin;}pos[6]=width;pos[7]=height;BufferedImage targetImage= new BufferedImage(width, height, BufferedImage.TYPE_4BYTE_ABGR);Integer[][] templateImage = getSmallImg(pos);cutByTemplate(oriImage,targetImage,templateImage,pos);ImageIO.write(oriImage, "jpg", file2);ImageIO.write(targetImage, "png", file1);}}

2.接受结果的实体类
需要注意:
1.bigImg是大图的base64,smallImg是小图的base64。
2.posY 是小图相对大图的y坐标,posX是小图相对大图的x坐标,我们拿到PuzzleInfo 对象时,需要把posX保存在缓存中,并赋值0。
前端将移动距离传回后端,只需与缓存中的posX对比,差值的绝对值小于5即可。


import lombok.Data;@Data
public class PuzzleInfo {private String bigImg;private String smallImg;private Integer posY;private Integer posX;private Integer smallWidth;private Integer smallHeight;private Integer bigWidth;private Integer bigHeight;
}

准备图片资源

保持格式和图片名如下,除非修改获取资源部分的代码,否则报错找不到图片资源。如果保持这样还报错,说明图片未编译到target目录,把target删除,重新编译。

更多推荐

java后端实现滑块拼图验证

本文发布于:2024-03-23 17:50:31,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1741033.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:拼图   后端   滑块   java

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!