diff --git a/src/main/scala/lc/RainDropsCaptcha.scala b/src/main/scala/lc/RainDropsCaptcha.scala index 8ff7383..b14126d 100644 --- a/src/main/scala/lc/RainDropsCaptcha.scala +++ b/src/main/scala/lc/RainDropsCaptcha.scala @@ -3,6 +3,7 @@ package lc import java.awt.image.BufferedImage import java.awt.RenderingHints import java.awt.Font +import java.awt.font.TextAttribute import java.awt.Color import java.io.ByteArrayOutputStream import javax.imageio.ImageIO @@ -23,19 +24,32 @@ class Drop { class RainDropsCP extends ChallengeProvider { private val alphabet = "abcdefghijklmnopqrstuvwxyz" private val n = 6 + private val bgColor = new Color(245, 245, 245) + private val textColor = new Color(248, 248, 248) + private val textHighlightColor = new Color(208, 208, 255) def getId = "FilterChallenge" + private def extendDrops(drops: Array[Drop], steps: Int, xOffset: Int) = { + drops.map(d => { + val nd = new Drop() + nd.x + xOffset*steps + nd.y + d.yOffset*steps + nd + }) + } + def returnChallenge(): Challenge = { val r = new scala.util.Random val secret = Stream.continually(r.nextInt(alphabet.size)).map(alphabet).take(n).mkString + // val secret = "mmmmmm" val width = 450 val height = 100 val imgType = BufferedImage.TYPE_INT_RGB val xOffset = 1+r.nextInt(2) val xBias = (height / 10) - 2 - val drops = Array.fill[Drop](1500)( new Drop()) - for (d <- drops) { + val dropsOrig = Array.fill[Drop](600)( new Drop()) + for (d <- dropsOrig) { d.x = r.nextInt(width) - (xBias/2)*xOffset d.yOffset = 6+r.nextInt(6) d.y = r.nextInt(height) @@ -44,10 +58,17 @@ class RainDropsCP extends ChallengeProvider { d.colorChange *= -1 } } + val drops = dropsOrig ++ extendDrops(dropsOrig, 2, xOffset) ++ extendDrops(dropsOrig, 4, xOffset) + + val baseFont = new Font(Font.MONOSPACED, Font.BOLD, 80) + val attributes = new java.util.HashMap[TextAttribute, Object]() + attributes.put(TextAttribute.TRACKING, Double.box(0.2)) + attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT_EXTRABOLD) + val spacedFont = baseFont.deriveFont(attributes) val baos = new ByteArrayOutputStream(); val ios = new MemoryCacheImageOutputStream(baos); - val writer = new GifSequenceWriter(ios, imgType, 100, true); + val writer = new GifSequenceWriter(ios, imgType, 60, true); for(i <- 0 until 30){ val yOffset = 5+r.nextInt(5) val canvas = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB) @@ -55,7 +76,7 @@ class RainDropsCP extends ChallengeProvider { g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON) // clear the canvas - g.setColor(Color.WHITE) + g.setColor(bgColor) g.fillRect(0, 0, canvas.getWidth, canvas.getHeight) // paint the rain @@ -66,8 +87,10 @@ class RainDropsCP extends ChallengeProvider { d.y += d.yOffset d.color += d.colorChange if (d.x > width+xOffset || d.y > height+d.yOffset) { - d.x = r.nextInt(width) - xBias*xOffset - d.y = 0 + val ySteps = 1 + height / d.yOffset + d.x -= xOffset*ySteps + d.y -= yOffset*ySteps + } if (d.color > 200 || d.color < 21) { d.colorChange *= -1 @@ -75,15 +98,15 @@ class RainDropsCP extends ChallengeProvider { } // center the text - g.setFont(new Font("Sans", Font.BOLD, 70)) + g.setFont(spacedFont) val textWidth = g.getFontMetrics().charsWidth(secret.toCharArray, 0, secret.toCharArray.length) val textX = (width - textWidth)/2 // paint the top outline - g.setColor(Color.BLUE) + g.setColor(textHighlightColor) g.drawString(secret, textX, 69) // paint the text - g.setColor(Color.WHITE) + g.setColor(textColor) g.drawString(secret, textX, 70) g.dispose()