VerifyImageUtil.java
6.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
package com.jflyfox.api.util;
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.util.Map;
import java.util.Random;
public class VerifyImageUtil {
static int targetWidth = 55;//小图长
static int targetHeight = 45;//小图宽
static int circleR = 8;//半径
static int r1 = 4;//距离点
/**
* @return Map<String, Object> 返回生成的抠图和带抠图阴影的大图 base64码及抠图坐标
* @Description: 读取本地图片,生成拼图验证码
* @author zhoujin
*/
public static Map<String, Object> createImage(File file, Map<String, Object> resultMap) {
try {
BufferedImage oriImage = ImageIO.read(file);
Random random = new Random();
//X轴距离右端targetWidth Y轴距离底部targetHeight以上
int widthRandom = random.nextInt(oriImage.getWidth() - 2 * targetWidth) + targetWidth;
int heightRandom = random.nextInt(oriImage.getHeight() - targetHeight);
// log.info("原图大小{} x {},随机生成的坐标 X,Y 为({},{})",oriImage.getWidth(),oriImage.getHeight(),widthRandom,heightRandom);
BufferedImage targetImage = new BufferedImage(targetWidth, targetHeight, BufferedImage.TYPE_4BYTE_ABGR);
cutByTemplate(oriImage, targetImage, getBlockData(), widthRandom, heightRandom);
resultMap.put("bigImage", getImageBASE64(oriImage));//大图
resultMap.put("smallImage", getImageBASE64(targetImage));//小图
resultMap.put("xWidth", widthRandom);
resultMap.put("yHeight", heightRandom);
} catch (Exception e) {
} finally {
return resultMap;
}
}
/**
* @param oriImage 原图
* @param targetImage 抠图拼图
* @param templateImage 颜色
* @param x
* @param y void
* @throws
* @Createdate: 2019年1月24日上午10:51:30
* @Title: cutByTemplate
* @Description: 有这个轮廓后就可以依据这个二维数组的值来判定抠图并在原图上抠图位置处加阴影,
* @author zhoujin
*/
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();
return new Color(0, 0, 0, 1).getRGB();
}
/**
* @return int[][]
* @throws
* @Createdate: 2019年1月24日上午10:52:42
* @Title: getBlockData
* @Description: 生成小图轮廓
* @author zhoujin
*/
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;
}
/**
* @param image
* @return
* @throws IOException String
* @Title: getImageBASE64
* @Description: 图片转BASE64
* @author zhoujin
*/
public static String getImageBASE64(BufferedImage image) throws IOException {
byte[] imagedata = null;
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ImageIO.write(image, "png", bao);
imagedata = bao.toByteArray();
BASE64Encoder encoder = new BASE64Encoder();
String BASE64IMAGE = encoder.encodeBuffer(imagedata).trim();
BASE64IMAGE = BASE64IMAGE.replaceAll("\r|\n", ""); //删除 \r\n
return "data:image/png;base64," + BASE64IMAGE;
}
}