1
import java.awt.*;
2
import java.awt.image.*;
3
import java.io.*;
4
import java.util.Random;
5
import javax.servlet.*;
6
import javax.servlet.http.*;
7
8
import com.sun.image.codec.jpeg.*;
9
10
public class KeyImage extends HttpServlet
{
11
12
private static final String CONTENT_TYPE = "text/html; charset=GBK";
13
14
//Initialize global variables
15
public void init() throws ServletException
{
16
17
}
18
19
/**//**
20
* 隨機數生成器
21
*/
22
private static Random random = new Random();
23
24
/**//**
25
* 系統所有的字符
26
*/
27
private static Font[] fonts = GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
28
29
/**//**
30
* 排除的一些字體(這些字體會顯示不正常)
31
*/
32
private static java.util.Set excludeFonts = new java.util.HashSet();
33
34
static
{
35
excludeFonts.add("Cursor");
36
excludeFonts.add("Marlett");
37
excludeFonts.add("Symbol");
38
excludeFonts.add("Webdings");
39
excludeFonts.add("Wingdings");
40
excludeFonts.add("Wingdings 2");
41
}
42
43
/**//**
44
* 圖片的寬度
45
*/
46
private static int imageWidth = 90;
47
48
/**//**
49
* 圖片的高度
50
*/
51
private static int imageHeight = 30;
52
53
/**//**
54
* 背景顏色
55
*/
56
private static Color backgroundColor = Color.WHITE;
57
58
/**//**
59
* 輸出的字符數
60
*/
61
private static int characterNumber = 4;
62
63
/**//**
64
* 最終附加碼的字符串
65
*/
66
private StringBuffer keyBuf = null;
67
68
/**//**
69
* 字符的顏色數組
70
*/
71
private static Color[] colors = new Color[]
{Color.BLACK, Color.BLUE,
72
Color.CYAN, Color.DARK_GRAY, Color.GRAY, Color.GREEN, Color.MAGENTA,
73
Color.RED};
74
75
/**//**
76
* 獲得隨機的X值(范圍在5到9之間變化)
77
* @return int
78
*/
79
private int randomX()
{
80
return random.nextInt(5) + 5;
81
}
82
83
/**//**
84
* 獲得隨機的Y值(范圍在20到24之間變化)
85
* @return int
86
*/
87
private int randomY()
{
88
return random.nextInt(5) + 20;
89
}
90
91
/**//**
92
* 隨機產生字符的大小
93
* @return int 隨機字符大小
94
*/
95
private int randomSize()
{
96
return random.nextInt(5) + 20;
97
}
98
99
/**//**
100
* 隨機產生Font實例
101
* @return Font 隨機Font實例
102
*/
103
private Font randomFont()
{
104
Font font = null;
105
106
if (fonts != null)
{
107
font = fonts[random.nextInt(fonts.length)];
108
font = font.deriveFont(random.nextInt(3), randomSize());
109
} else
{
110
font = new Font("Arial Black", Font.PLAIN, 15);
111
}
112
113
while (excludeFonts.contains(font.getName()))
{
114
if (fonts != null)
{
115
font = fonts[random.nextInt(fonts.length)];
116
font = font.deriveFont(random.nextInt(3), randomSize());
117
} else
{
118
font = new Font("Arial Black", Font.PLAIN, 15);
119
}
120
}
121
122
log("Current Font: " + font.getName() + " Family: " + font.getFamily() + " Font Name: " + font.getFontName());
123
124
return font;
125
}
126
127
/**//**
128
* 隨機生成一個Color實例(除了背景)
129
* @return Color 隨機Color實例
130
*/
131
private Color randomColor()
{
132
int index = random.nextInt(colors.length);
133
log("Color index is: " + index);
134
135
return colors[index];
136
}
137
138
/**//**
139
* 寫入一個字符
140
* @param g Graphics
141
* @param x int
142
* @param y int
143
*/
144
private void drawCharacter(Graphics g, int x, int y)
{
145
int ri = (int) (Math.random() * 10); // 隨機生成的數字
146
keyBuf.append(ri);
147
g.setColor(randomColor());
148
g.setFont(randomFont());
149
g.drawString(String.valueOf(ri), x, y);
150
}
151
152
/**//**
153
* 繪制背景
154
* @param g Graphics
155
* @param color Color
156
* @param x int
157
* @param y int
158
* @param width int
159
* @param height int
160
*/
161
private void drawBackground(Graphics g, Color color, int x, int y, int width,
162
int height)
{
163
g.setColor(color);
164
g.fillRect(x, y, width, height);
165
}
166
167
/**//**
168
* 繪制干擾點,干擾線
169
* @param g Graphics
170
* @param width int
171
* @param height int
172
*/
173
private void drawInterrupt(Graphics g, int width, int height)
{
174
int numbers = random.nextInt(100) + 50; // 50到149個干擾點
175
g.setColor(Color.BLACK);
176
177
for (int i = 0; i < numbers; i++)
{
178
g.fillRect(random.nextInt(width), random.nextInt(height), 1, 1);
179
}
180
181
g.drawLine(0, random.nextInt(height), width, random.nextInt(height));
182
}
183
184
/**//**
185
* Process the HTTP Get request
186
* 隨機生成數字的策略:
187
* 1.隨機漸變色(包括文字和背景,暫時不實現)
188
* 2.所有可打印字符(這里暫時用數字)
189
* 3.字符大小隨機變化
190
* 4.位置不固定
191
* 5.象素行或列隨機錯位
192
* @param request HttpServletRequest
193
* @param response HttpServletResponse
194
* @throws ServletException
195
* @throws IOException
196
*/
197
public void doGet(HttpServletRequest request, HttpServletResponse response)
198
throws ServletException, IOException
{
199
200
BufferedImage image = new BufferedImage(imageWidth, imageHeight,
201
BufferedImage.TYPE_INT_RGB);
202
Graphics g = image.getGraphics();
203
204
drawBackground(g, backgroundColor, 0, 0, imageWidth, imageHeight);
205
206
keyBuf = new StringBuffer();
207
int offset = 0; // 偏移量
208
for (int i = 0; i < characterNumber; i++)
{
209
drawCharacter(g, randomX() + offset, randomY());
210
offset += imageWidth / characterNumber;
211
}
212
213
drawInterrupt(g, imageWidth, imageHeight);
214
215
response.setHeader("Cache-Control", "no-store");
216
response.setDateHeader("Expires", 0);
217
response.setContentType("image/jpeg");
218
219
ServletOutputStream out = response.getOutputStream();
220
221
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
222
encoder.encode(image);
223
out.close();
224
225
// 保存附加碼
226
request.getSession().setAttribute("_key", keyBuf.toString());
227
log("The addtional code is: " + keyBuf.toString());
228
}
229
230
//Clean up resources
231
public void destroy()
{
232
}
233
234
/**//**
235
* 改寫服務器日志的輸出
236
* @param msg String 要輸出的信息
237
*/
238
public void log(String msg)
{
239
super.log(msg);
240
}
241
242
/**//**
243
* 改寫服務器日志的輸出
244
* @param message String 要輸出的信息
245
* @param t Throwable 拋出的意外
246
*/
247
public void log(String message, Throwable t)
{
248
t.printStackTrace(System.out);
249
super.log(message, t);
250
}
251
}

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

194

195

196

197

198



199

200

201

202

203

204

205

206

207

208



209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231



232

233

234


235

236

237

238



239

240

241

242


243

244

245

246

247



248

249

250

251

附加碼的效果圖: