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