Java工具--滑塊驗證碼生成
阿新 • • 發佈:2019-01-25
1概述
針對當前網際網路流行的滑塊驗證碼,這裡做了一個工具,適用於前後端分離的專案。工具將摳圖和摳圖後的原圖以位元組碼的形式輸出。
2工具原始碼
package com.liutao.util; import javax.imageio.ImageIO; import javax.imageio.ImageReadParam; import javax.imageio.ImageReader; import javax.imageio.stream.ImageInputStream; import java.awt.*; import java.awt.image.BufferedImage; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.InputStream; import java.text.NumberFormat; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Random; /** * 滑塊驗證工具類 * * @author: LIUTAO * @Description: * @Date: Created in 10:57 2018/6/25 * @Modified By: */ public class VerifyImageUtil { private static int ORI_WIDTH = 590; //原始檔寬度 private static int ORI_HEIGHT = 360; //原始檔高度 private static int X; //摳圖座標x private static int Y; //摳圖座標y private static int WIDTH; //模板圖寬度 private static int HEIGHT; //模板圖高度 private static float xPercent; //X位置移動百分比 private static float yPercent; //Y位置移動百分比 public static int getX() { return X; } public static int getY() { return Y; } public static float getxPercent() { return xPercent; } public static float getyPercent() { return yPercent; } /** * 根據模板切圖 * newImage:摳圖直位元組碼 * oriCopyImage:原圖位元組碼 * * @param templateFile * @param targetFile * @param templateType * @param targetType * @return * @throws Exception */ public static Map<String, byte[]> pictureTemplatesCut(File templateFile, File targetFile, String templateType, String targetType) throws Exception { Map<String, byte[]> pictureMap = new HashMap<>(); // 檔案型別 String templateFiletype = templateType; String oriFiletype = targetType; if (StringUtils.isEmpty(templateFiletype) || StringUtils.isEmpty(oriFiletype)) { throw new RuntimeException("file type is empty"); } // 原始檔流 File Orifile = targetFile; InputStream oriis = new FileInputStream(Orifile); // 模板圖 BufferedImage imageTemplate = ImageIO.read(templateFile); WIDTH = imageTemplate.getWidth(); HEIGHT = imageTemplate.getHeight(); generateCutoutCoordinates(); // 最終影象 BufferedImage newImage = new BufferedImage(WIDTH, HEIGHT, imageTemplate.getType()); Graphics2D graphics = newImage.createGraphics(); graphics.setBackground(Color.white); int bold = 5; // 獲取感興趣的目標區域 BufferedImage targetImageNoDeal = getTargetArea(X, Y, WIDTH, HEIGHT, oriis, oriFiletype); // 根據模板圖片摳圖 newImage = DealCutPictureByTemplate(targetImageNoDeal, imageTemplate, newImage); // 設定“抗鋸齒”的屬性 graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); graphics.setStroke(new BasicStroke(bold, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL)); graphics.drawImage(newImage, 0, 0, null); graphics.dispose(); ByteArrayOutputStream os = new ByteArrayOutputStream();//新建流。 ImageIO.write(newImage, "png", os);//利用ImageIO類提供的write方法,將bi以png圖片的資料模式寫入流。 byte[] newImages = os.toByteArray(); pictureMap.put("newImage", newImages); // 源圖生成遮罩 BufferedImage oriImage = ImageIO.read(Orifile); byte[] oriCopyImages = DealOriPictureByTemplate(oriImage, imageTemplate, X, Y); pictureMap.put("oriCopyImage", oriCopyImages); return pictureMap; } /** * 摳圖後原圖生成 * * @param oriImage * @param templateImage * @param x * @param y * @return * @throws Exception */ private static byte[] DealOriPictureByTemplate(BufferedImage oriImage, BufferedImage templateImage, int x, int y) throws Exception { // 原始檔備份影象矩陣 支援alpha通道的rgb影象 BufferedImage ori_copy_image = new BufferedImage(oriImage.getWidth(), oriImage.getHeight(), BufferedImage.TYPE_4BYTE_ABGR); // 原始檔影象矩陣 int[][] oriImageData = getData(oriImage); // 模板影象矩陣 int[][] templateImageData = getData(templateImage); //copy 源圖做不透明處理 for (int i = 0; i < oriImageData.length; i++) { for (int j = 0; j < oriImageData[0].length; j++) { int rgb = oriImage.getRGB(i, j); int r = (0xff & rgb); int g = (0xff & (rgb >> 8)); int b = (0xff & (rgb >> 16)); //無透明處理 rgb = r + (g << 8) + (b << 16) + (255 << 24); ori_copy_image.setRGB(i, j, rgb); } } for (int i = 0; i < templateImageData.length; i++) { for (int j = 0; j < templateImageData[0].length - 5; j++) { int rgb = templateImage.getRGB(i, j); //對原始檔備份影象(x+i,y+j)座標點進行透明處理 if (rgb != 16777215 && rgb <= 0) { int rgb_ori = ori_copy_image.getRGB(x + i, y + j); int r = (0xff & rgb_ori); int g = (0xff & (rgb_ori >> 8)); int b = (0xff & (rgb_ori >> 16)); rgb_ori = r + (g << 8) + (b << 16) + (150 << 24); ori_copy_image.setRGB(x + i, y + j, rgb_ori); } else { //do nothing } } } ByteArrayOutputStream os = new ByteArrayOutputStream();//新建流。 ImageIO.write(ori_copy_image, "png", os);//利用ImageIO類提供的write方法,將bi以png圖片的資料模式寫入流。 byte b[] = os.toByteArray();//從流中獲取資料陣列。 return b; } /** * 根據模板圖片摳圖 * * @param oriImage * @param templateImage * @return */ private static BufferedImage DealCutPictureByTemplate(BufferedImage oriImage, BufferedImage templateImage, BufferedImage targetImage) throws Exception { // 原始檔影象矩陣 int[][] oriImageData = getData(oriImage); // 模板影象矩陣 int[][] templateImageData = getData(templateImage); // 模板影象寬度 for (int i = 0; i < templateImageData.length; i++) { // 模板圖片高度 for (int j = 0; j < templateImageData[0].length; j++) { // 如果模板影象當前畫素點不是白色 copy原始檔資訊到目標圖片中 int rgb = templateImageData[i][j]; if (rgb != 16777215 && rgb <= 0) { targetImage.setRGB(i, j, oriImageData[i][j]); } } } return targetImage; } /** * 獲取目標區域 * * @param x 隨機切圖座標x軸位置 * @param y 隨機切圖座標y軸位置 * @param targetWidth 切圖後目標寬度 * @param targetHeight 切圖後目標高度 * @param ois 原始檔輸入流 * @return * @throws Exception */ private static BufferedImage getTargetArea(int x, int y, int targetWidth, int targetHeight, InputStream ois, String filetype) throws Exception { Iterator<ImageReader> imageReaderList = ImageIO.getImageReadersByFormatName(filetype); ImageReader imageReader = imageReaderList.next(); // 獲取圖片流 ImageInputStream iis = ImageIO.createImageInputStream(ois); // 輸入源中的影象將只按順序讀取 imageReader.setInput(iis, true); ImageReadParam param = imageReader.getDefaultReadParam(); Rectangle rec = new Rectangle(x, y, targetWidth, targetHeight); param.setSourceRegion(rec); BufferedImage targetImage = imageReader.read(0, param); return targetImage; } /** * 生成影象矩陣 * * @param * @return * @throws Exception */ private static int[][] getData(BufferedImage bimg) throws Exception { int[][] data = new int[bimg.getWidth()][bimg.getHeight()]; for (int i = 0; i < bimg.getWidth(); i++) { for (int j = 0; j < bimg.getHeight(); j++) { data[i][j] = bimg.getRGB(i, j); } } return data; } /** * 隨機生成摳圖座標 */ private static void generateCutoutCoordinates() { Random random = new Random(); int widthDifference = ORI_WIDTH - WIDTH; int heightDifference = ORI_HEIGHT - HEIGHT; if (widthDifference <= 0) { X = 5; } else { X = random.nextInt(ORI_WIDTH - WIDTH) + 5; } if (heightDifference <= 0) { Y = 5; } else { Y = random.nextInt(ORI_HEIGHT - HEIGHT) + 5; } NumberFormat numberFormat = NumberFormat.getInstance(); numberFormat.setMaximumFractionDigits(2); xPercent = Float.parseFloat(numberFormat.format((float) X / (float) ORI_WIDTH)); yPercent = Float.parseFloat(numberFormat.format((float) Y / (float) ORI_HEIGHT)); } }
3測試程式碼
public void testImg() throws Exception { Map<String, byte[]> pictureMap; File templateFile; //模板圖片 File targetFile; // Random random = new Random(); int templateNo = random.nextInt(4) + 1; int targetNo = random.nextInt(20) + 1; InputStream stream = getClass().getClassLoader().getResourceAsStream("static/templates/" + templateNo + ".png"); templateFile = new File(templateNo + ".png"); FileUtils.copyInputStreamToFile(stream, templateFile); stream = getClass().getClassLoader().getResourceAsStream("static/targets/" + targetNo + ".jpg"); targetFile = new File(targetNo + ".jpg"); FileUtils.copyInputStreamToFile(stream, targetFile); pictureMap = VerifyImageUtil.pictureTemplatesCut(templateFile, targetFile, "png", "jpg"); byte[] oriCopyImages = pictureMap.get("oriCopyImage"); byte[] newImages = pictureMap.get("newImage"); FileOutputStream fout = new FileOutputStream("C:/Users/Administrator/Desktop/oriCopyImage.png"); //將位元組寫入檔案 try { fout.write(oriCopyImages); } catch (IOException e) { e.printStackTrace(); } fout.close(); FileOutputStream newImageFout = new FileOutputStream("C:/Users/Administrator/Desktop/newImage.png"); //將位元組寫入檔案 newImageFout.write(newImages); newImageFout.close(); }
以上就是滑塊驗證碼的使用示例。具體的圖片資源和原始碼請參考:滑塊驗證碼。
有疑問請在下方評論區留言。歡迎交流!