1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.custom.captcha.util;
20
21 import java.awt.Color;
22 import java.awt.Font;
23 import java.awt.GradientPaint;
24 import java.awt.Graphics;
25 import java.awt.Graphics2D;
26 import java.awt.RenderingHints;
27 import java.awt.font.TextLayout;
28 import java.awt.image.BufferedImage;
29 import java.io.IOException;
30 import java.util.Random;
31
32 import javax.servlet.http.HttpServletResponse;
33
34 import org.apache.batik.ext.awt.image.codec.PNGEncodeParam;
35 import org.apache.batik.ext.awt.image.codec.PNGImageEncoder;
36
37
38
39
40
41
42 public class CAPTCHAImageGenerator
43 {
44
45
46
47
48
49
50
51 private void drawTextOnImage(Graphics2D graphics, String captchaText)
52 {
53
54 Font font;
55 TextLayout textLayout;
56 double currentFontStatus = Math.random();
57
58
59 if (currentFontStatus >= 0.5)
60 {
61 font = new Font("Arial", Font.PLAIN, 60);
62 }
63 else
64 {
65 font = new Font("Arial", Font.BOLD, 60);
66 }
67
68 graphics.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
69 RenderingHints.VALUE_ANTIALIAS_ON);
70 textLayout = new TextLayout(captchaText, font, graphics
71 .getFontRenderContext());
72
73 textLayout.draw(graphics, CAPTCHAConstants.TEXT_X_COORDINATE,
74 CAPTCHAConstants.TEXT_Y_COORDINATE);
75 }
76
77
78
79
80 private void applyNoiseOnImage(Graphics2D graphics, int bufferedImageWidth,
81 int bufferedImageHeight, Color startingColor, Color endingColor)
82 {
83
84
85 applyShear(graphics, bufferedImageWidth, bufferedImageHeight,
86 startingColor, endingColor);
87
88
89 drawBrokenLineOnImage(graphics);
90 }
91
92
93
94
95
96 private static void applyCurrentGradientPaint(Graphics2D graphics,
97 int width, int height, Color startingColor, Color endingColor)
98 {
99
100 GradientPaint gradientPaint = new GradientPaint(0, 0, startingColor,
101 width, height, endingColor);
102
103 graphics.setPaint(gradientPaint);
104 }
105
106
107
108
109
110
111
112
113
114 public void generateImage(HttpServletResponse response, String captchaText,
115 Color startingColor, Color endingColor) throws IOException
116 {
117
118 BufferedImage bufferedImage;
119 Graphics2D graphics;
120 PNGEncodeParam param;
121 PNGImageEncoder captchaPNGImage;
122
123
124 bufferedImage = new BufferedImage(
125 CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH,
126 CAPTCHAConstants.DEFAULT_CAPTCHA_HEIGHT,
127 BufferedImage.TYPE_BYTE_INDEXED);
128
129
130 graphics = bufferedImage.createGraphics();
131
132 applyCurrentGradientPaint(graphics, bufferedImage.getWidth(),
133 bufferedImage.getHeight(), startingColor, endingColor);
134
135 graphics.fillRect(0, 0, bufferedImage.getWidth(), bufferedImage
136 .getHeight());
137
138 graphics.setColor(Color.black);
139
140
141 drawTextOnImage(graphics, captchaText);
142
143
144 applyNoiseOnImage(graphics, bufferedImage.getWidth(), bufferedImage
145 .getHeight(), startingColor, endingColor);
146
147
148 drawBorders(graphics, bufferedImage.getWidth(), bufferedImage
149 .getHeight());
150
151
152 response.setContentType("image/jpg");
153
154 param = PNGEncodeParam.getDefaultEncodeParam(bufferedImage);
155 captchaPNGImage = new PNGImageEncoder(response.getOutputStream(), param);
156
157 captchaPNGImage.encode(bufferedImage);
158 }
159
160
161
162
163 private void drawThickLineOnImage(Graphics graphics, int x1, int y1,
164 int x2, int y2)
165 {
166
167 int dX = x2 - x1;
168 int dY = y2 - y1;
169 int xPoints[] = new int[4];
170 int yPoints[] = new int[4];
171 int thickness = 2;
172
173 double lineLength = Math.sqrt(dX * dX + dY * dY);
174 double scale = (double) (thickness) / (2 * lineLength);
175 double ddx = -scale * (double) dY;
176 double ddy = scale * (double) dX;
177
178 graphics.setColor(Color.black);
179
180 ddx += (ddx > 0) ? 0.5 : -0.5;
181 ddy += (ddy > 0) ? 0.5 : -0.5;
182 dX = (int) ddx;
183 dY = (int) ddy;
184
185 xPoints[0] = x1 + dX;
186 yPoints[0] = y1 + dY;
187 xPoints[1] = x1 - dX;
188 yPoints[1] = y1 - dY;
189 xPoints[2] = x2 - dX;
190 yPoints[2] = y2 - dY;
191 xPoints[3] = x2 + dX;
192 yPoints[3] = y2 + dY;
193
194 graphics.fillPolygon(xPoints, yPoints, 4);
195 }
196
197
198
199
200 private void drawBrokenLineOnImage(Graphics2D graphics)
201 {
202
203 int yPoint1;
204 int yPoint2;
205 int yPoint3;
206 int yPoint4;
207 int yPoint5;
208 Random random = new Random();
209
210
211 yPoint1 = random.nextInt(CAPTCHAConstants.DEFAULT_CAPTCHA_HEIGHT);
212 yPoint2 = random.nextInt(CAPTCHAConstants.DEFAULT_CAPTCHA_HEIGHT);
213 yPoint3 = CAPTCHAConstants.DEFAULT_CAPTCHA_HEIGHT / 2;
214 yPoint4 = random.nextInt(CAPTCHAConstants.DEFAULT_CAPTCHA_HEIGHT);
215 yPoint5 = random.nextInt(CAPTCHAConstants.DEFAULT_CAPTCHA_HEIGHT);
216
217
218 drawThickLineOnImage(graphics, 0, yPoint1,
219 CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH / 4, yPoint2);
220 drawThickLineOnImage(graphics,
221 CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH / 4, yPoint2,
222 CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH / 2, yPoint3);
223 drawThickLineOnImage(graphics,
224 CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH / 2, yPoint3,
225 3 * CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH / 4, yPoint4);
226 drawThickLineOnImage(graphics,
227 3 * CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH / 4, yPoint4,
228 CAPTCHAConstants.DEFAULT_CAPTCHA_WIDTH, yPoint5);
229 }
230
231
232
233
234
235 private double getDelta(int period, double i, double phase, double frames)
236 {
237 return (double) (period / 2)
238 * Math.sin(i / (double) period
239 + (2 * CAPTCHAConstants.PI * phase) / frames);
240 }
241
242
243
244
245 private void applyShear(Graphics2D graphics, int bufferedImageWidth,
246 int bufferedImageHeight, Color startingColor, Color endingColor)
247 {
248
249 int periodValue = 20;
250 int numberOfFrames = 15;
251 int phaseNumber = 7;
252 double deltaX;
253 double deltaY;
254
255 applyCurrentGradientPaint(graphics, bufferedImageWidth,
256 bufferedImageHeight, startingColor, endingColor);
257
258 for (int i = 0; i < bufferedImageWidth; ++i)
259 {
260 deltaX = getDelta(periodValue, i, phaseNumber, numberOfFrames);
261 graphics.copyArea(i, 0, 1, bufferedImageHeight, 0, (int) deltaX);
262 graphics.drawLine(i, (int) deltaX, i, 0);
263 graphics.drawLine(i, (int) deltaX + bufferedImageHeight, i,
264 bufferedImageHeight);
265 }
266
267 for (int i = 0; i < bufferedImageHeight; ++i)
268 {
269 deltaY = getDelta(periodValue, i, phaseNumber, numberOfFrames);
270 graphics.copyArea(0, i, bufferedImageWidth, 1, (int) deltaY, 0);
271 graphics.drawLine((int) deltaY, i, 0, i);
272 graphics.drawLine((int) deltaY + bufferedImageWidth, i,
273 bufferedImageWidth, i);
274 }
275 }
276
277
278
279
280 private void drawBorders(Graphics2D graphics, int width, int height)
281 {
282 graphics.setColor(Color.black);
283
284 graphics.drawLine(0, 0, 0, width - 1);
285 graphics.drawLine(0, 0, width - 1, 0);
286 graphics.drawLine(0, height - 1, width, height - 1);
287 graphics.drawLine(width - 1, height - 1, width - 1, 0);
288 }
289
290 }