1 16 package org.apache.cocoon.reading; 17 18 import java.awt.Color ; 19 import java.awt.Font ; 20 import java.awt.FontMetrics ; 21 import java.awt.Graphics2D ; 22 import java.awt.Image ; 23 import java.awt.RenderingHints ; 24 import java.awt.geom.Rectangle2D ; 25 import java.awt.image.BufferedImage ; 26 import java.awt.image.WritableRaster ; 27 import java.io.ByteArrayOutputStream ; 28 import java.io.IOException ; 29 import java.lang.reflect.Field ; 30 import java.util.Random ; 31 32 import com.sun.image.codec.jpeg.JPEGCodec; 33 import com.sun.image.codec.jpeg.JPEGEncodeParam; 34 import com.sun.image.codec.jpeg.JPEGImageEncoder; 35 36 99 public class CaptchaReader extends AbstractReader { 100 101 102 private static final Random RANDOM = new Random (); 103 104 109 public String getMimeType() { 110 return "image/jpeg"; 111 } 112 113 120 private Color getColor(String parameterName, Color defaultColor) { 121 String colorString = this.parameters.getParameter(parameterName, null); 122 if (colorString == null) return defaultColor; 123 try { 124 return Color.decode(colorString); 125 } catch (Exception e1) { 126 try { 127 Field colorField = Color .class.getDeclaredField(colorString); 128 return (Color ) colorField.get(Color .class); 129 } catch (Exception e2) { 130 return defaultColor; 131 } 132 } 133 } 134 135 private Graphics2D antialiasedGraphics(BufferedImage image) { 136 Graphics2D graphics = image.createGraphics(); 137 graphics.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, 138 RenderingHints.VALUE_TEXT_ANTIALIAS_ON); 139 return graphics; 140 } 141 142 148 public void generate() 149 throws IOException { 150 151 152 final int width = this.parameters.getParameterAsInteger("width", 100); 153 final int height = this.parameters.getParameterAsInteger("height", 50); 154 Color background = this.getColor("background", Color.white); 155 Color foreground = this.getColor("foreground", null); 156 if (foreground == null) { 157 int r = (RANDOM.nextInt(64) + 96 + background.getRed()) & 0x0ff; 158 int g = (RANDOM.nextInt(64) + 96 + background.getGreen()) & 0x0ff; 159 int b = (RANDOM.nextInt(64) + 96 + background.getBlue()) & 0x0ff; 160 foreground = new Color (r, g, b); 161 } 162 final String fontName = this.parameters.getParameter("font", "serif"); 163 final int scale = this.parameters.getParameterAsInteger("scale", 5); 164 final float amount = this.parameters.getParameterAsFloat("amount", 2); 165 final float quality = this.parameters.getParameterAsFloat("quality", 0.75F); 166 final String text = this.source; 167 168 169 final BufferedImage result = new BufferedImage (width, height, 170 BufferedImage.TYPE_INT_RGB); 171 172 173 final Font baseFont = new Font (fontName, Font.PLAIN, 100); 174 final Graphics2D graphics = this.antialiasedGraphics(result); 175 final FontMetrics metrics = graphics.getFontMetrics(baseFont); 176 final Rectangle2D tempSize = metrics.getStringBounds(text, graphics); 177 178 179 final double tempWidth = tempSize.getWidth() + (2 * tempSize.getHeight()); 180 final double tempHeight = (tempSize.getHeight() * (1 + amount)); 181 final double ratioWidth = width * scale / tempWidth; 182 final double ratioHeight = height * scale / tempHeight; 183 final double ratio = ratioWidth < ratioHeight? ratioWidth: ratioHeight; 184 final Font font = baseFont.deriveFont((float) (100 * ratio)); 185 186 187 final FontMetrics sourceMetrics = graphics.getFontMetrics(font); 188 final Rectangle2D size = sourceMetrics.getStringBounds(text, graphics); 189 final double textWidth = size.getWidth(); 190 final double textHeight = size.getHeight(); 191 192 193 int scaledWidth = (int) (tempWidth * ratio); 194 int scaledHeight = (int) (tempHeight * ratio); 195 196 197 BufferedImage source = new BufferedImage (scaledWidth, scaledHeight, 198 BufferedImage.TYPE_BYTE_GRAY); 199 BufferedImage warped = new BufferedImage (scaledWidth, scaledHeight, 200 BufferedImage.TYPE_INT_ARGB); 201 202 203 final Graphics2D sourceGraphics = this.antialiasedGraphics(source); 204 sourceGraphics.setColor(Color.black); 205 sourceGraphics.fillRect(0, 0, scaledWidth, scaledHeight); 206 sourceGraphics.setFont(font); 207 208 209 float textX = (float) ((scaledWidth - textWidth) / 2); 210 float textY = (float) ((scaledHeight - textHeight) / 2); 211 sourceGraphics.setColor(Color.white); 212 sourceGraphics.drawString(text, textX, textY + sourceMetrics.getAscent()); 213 214 215 final int displaceTop = RANDOM.nextInt(scaledWidth); 216 final int displaceBtm = RANDOM.nextInt(scaledWidth); 217 final int displaceVer = RANDOM.nextInt(scaledHeight); 218 219 220 final double amplitHor = textHeight * amount / 4; 221 final double amplitVer = textHeight / 8; 222 final double t = (RANDOM.nextDouble() * textWidth / 2) + (textWidth * 0.75); 223 final double b = (RANDOM.nextDouble() * textWidth / 2) + (textWidth * 0.75); 224 final double wlenTop = textHeight > t? textHeight: t; 225 final double wlenBtm = textHeight > b? textHeight: b; 226 227 228 final double offsetTop = amplitHor; 229 final double offsetBtm = scaledHeight - amplitHor; 230 231 232 final double vert[] = new double[scaledHeight]; 233 for (int v = 0; v < scaledHeight ; v++) { 234 vert[v] = Math.sin((Math.PI * (v + displaceVer)) / textHeight) * amplitVer; 235 } 236 237 238 int x1 = Integer.MAX_VALUE; 239 int x2 = Integer.MIN_VALUE; 240 int y1 = Integer.MAX_VALUE; 241 int y2 = Integer.MIN_VALUE; 242 final WritableRaster sourceRaster = source.getRaster(); 243 final WritableRaster warpedRaster = warped.getRaster(); 244 final double src[] = new double[9]; 245 final double col[] = new double[] { foreground.getRed(), 246 foreground.getGreen(), 247 foreground.getBlue(), 0}; 248 for (int h = 0; h < scaledWidth; h++) { 249 final double baseTop = (Math.PI * (h + displaceTop)) / wlenTop; 250 final double baseBtm = (Math.PI * (h + displaceBtm)) / wlenBtm; 251 final double top = offsetTop + Math.sin(baseTop) * amplitHor; 252 final double btm = offsetBtm - Math.sin(baseBtm) * amplitHor; 253 254 for (int v = 0; v < scaledHeight; v ++) { 255 final double x = (h + vert[v]); 256 final double y = (v * ((btm - top) / scaledHeight)) + top; 257 258 if ((y > 0) && (y < scaledHeight - 1) && 259 (x > 0) && (x < scaledWidth - 1)) { 260 261 262 sourceRaster.getPixels((int)(x-1), (int)(y-1), 3, 3, src); 263 264 265 double alpha = ((src[1] + src[3] + src[5] + src[7]) * 0.1) + 266 ((src[0] + src[2] + src[6] + src[8]) * 0.025) + 267 (src[4] * 0.5); 268 269 270 if (alpha > 0) { 271 col[3] = alpha; 272 warpedRaster.setPixel(h, v, col); 273 if (h < x1) x1 = h; 274 if (h > x2) x2 = h; 275 if (v < y1) y1 = v; 276 if (v > y2) y2 = v; 277 } 278 } 279 } 280 } 281 282 283 source = null; 284 int xd = x2 - x1 + 1; 285 int yd = y2 - y1 + 1; 286 if ((xd > 1) && (yd > 1)) { 287 warped = warped.getSubimage(x1, y1, xd, yd); 288 } 289 290 291 Image image = warped.getScaledInstance(width, height, Image.SCALE_SMOOTH); 292 graphics.setBackground(background); 293 graphics.setColor(background); 294 graphics.fillRect(0, 0, width, height); 295 graphics.setColor(foreground); 296 graphics.drawImage(image, 0, 0, null); 297 warped = null; 298 299 300 ByteArrayOutputStream buffer = new ByteArrayOutputStream (); 301 JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(buffer); 302 JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(result); 303 param.setQuality(quality, true); 304 encoder.encode(result, param); 305 buffer.flush(); 306 buffer.close(); 307 this.out.write(buffer.toByteArray()); 308 this.out.flush(); 309 } 310 } 311 | Popular Tags |