Saturday, May 7, 2011

Captcha Programming

Captcha Programming in Java



package com.jit;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Iterator;

import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @author Vinay Guntaka
 * Servlet implementation class CaptchaServlet
 */
public class CaptchaServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
     
    /**
     * @see HttpServlet#HttpServlet()
     */
    public CaptchaServlet() {
        super();
    }

    /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        createCatcha(request, response);
    }

    /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
     */
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        createCatcha(request, response);
    }
    @SuppressWarnings("unchecked")
    protected void createCatcha(HttpServletRequest request,HttpServletResponse response)throws ServletException, IOException {

        response.setContentType("image/jpg");

         try {
            Color textColor = Color.white;
            Font textFont = new Font("Georgia", Font.PLAIN, 18);
            int charsToPrint = 6;
            int width = 125;
            int height = 28;
            float horizMargin = 20.0f;
            float imageQuality = 0.95f; // max is 1.0 (this is for jpeg)
            double rotationRange = 0.7; // this is radians
            BufferedImage bufferedImage = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);

            Graphics2D g = (Graphics2D) bufferedImage.getGraphics();

            // Draw an oval
            g.setColor(new Color(255, 153, 0));
            g.fillRect(0, 0, width, height);
            g.setColor(textColor);
            g.setFont(textFont);

            FontMetrics fontMetrics = g.getFontMetrics();
            int maxAdvance = fontMetrics.getMaxAdvance();
            int fontHeight = fontMetrics.getHeight();

            // i removed 1 and l and i because there are confusing to users...
            // Z, z, and N also get confusing when rotated
            // 0, O, and o are also confusing...
            // lowercase G looks a lot like a 9 so i killed it
            // this should ideally be done for every language...
            // i like controlling the characters though because it helps prevent
            // confusion
            String elegibleChars = "ABCDEFGHJKLMPQRSTUVWXYabcdefhjkmnpqrstuvwxy23456789";
            char[] chars = elegibleChars.toCharArray();

            float spaceForLetters = -horizMargin * 2 + width;
            float spacePerChar = spaceForLetters / (charsToPrint - 1.0f);
            StringBuffer finalString = new StringBuffer();

            for (int i = 0; i < charsToPrint; i++) {
                double randomValue = Math.random();
                int randomIndex = (int) Math.round(randomValue*(chars.length - 1));
                char characterToShow = chars[randomIndex];
                finalString.append(characterToShow);
                int charWidth = fontMetrics.charWidth(characterToShow);
                int charDim = Math.max(maxAdvance, fontHeight);
                int halfCharDim = (int) (charDim / 2);

                BufferedImage charImage = new BufferedImage(charDim, charDim,BufferedImage.TYPE_INT_ARGB);
                Graphics2D charGraphics = charImage.createGraphics();
                charGraphics.translate(halfCharDim, halfCharDim);
                double angle = (Math.random() - 0.5) * rotationRange;
                charGraphics.transform(AffineTransform.getRotateInstance(angle));
                charGraphics.translate(-halfCharDim, -halfCharDim);
                charGraphics.setColor(textColor);
                charGraphics.setFont(textFont);

                int charX = (int) (0.5 * charDim - 0.5 * charWidth);
                charGraphics.drawString("" + characterToShow,charX,
                                (int) ((charDim - fontMetrics.getAscent()) / 2 + fontMetrics
                                        .getAscent()));

                float x = horizMargin + spacePerChar * (i) - charDim / 2.0f;
                int y = (int) ((height - charDim) / 2);
                g.drawImage(charImage, (int) x, y, charDim, charDim,null, null);

                charGraphics.dispose();
            }

            // Write the image as a jpg
            Iterator iter = ImageIO.getImageWritersByFormatName("JPG");
            if (iter.hasNext()) {
                ImageWriter writer = (ImageWriter) iter.next();
                ImageWriteParam iwp = writer.getDefaultWriteParam();
                iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
                iwp.setCompressionQuality(imageQuality);
                writer.setOutput(ImageIO.createImageOutputStream(response.getOutputStream()));
                IIOImage imageIO = new IIOImage(bufferedImage, null, null);
                writer.write(null, imageIO, iwp);
            } else {
                throw new RuntimeException("no encoder found for jsp");
            }

            // let's stick the final string in the session
            request.getSession().setAttribute("captcha", finalString.toString());
            g.dispose();

        } catch (IOException ioe) {
            throw new RuntimeException("Unable to build image", ioe);
        }

    }

}

----------------------------------
Captcha.jsp

<%@page contentType="text/html" pageEncoding="UTF-8"%>


<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Captcha</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<center>
<form method="post">
<table cellspacing="15">
<tr>
<td>Are you human?</td>
<td><input type="text" name="code"></td>
</tr>

</table>

<br>
<img src="CaptchaServlet">

<br><br>
<input type="submit" value="submit">

</form>
<br><br>
<%
  String captcha = (String) session.getAttribute("captcha");
  String code = (String) request.getParameter("code");

  if (captcha != null && code != null) {

      System.out.println("Captcha Code:"+captcha);
      System.out.println("Code:"+code);

    if (captcha.equals(code)) {
      out.print("<p class='alert'>Correct</p>");
    } else {
          out.print("<p class='alert'>Incorrect</p>");
    }
  }
%>
</center>
</body>
</html>

--------------------------------
web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>Captcha</display-name>
  <welcome-file-list>
    <welcome-file>captcha.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <description></description>
    <display-name>CaptchaServlet</display-name>
    <servlet-name>CaptchaServlet</servlet-name>
    <servlet-class>com.jit.CaptchaServlet</servlet-class>;
  </servlet>
  <servlet-mapping>
    <servlet-name>CaptchaServlet</servlet-name>
    <url-pattern>/CaptchaServlet</url-pattern>
  </servlet-mapping>
</web-app>



No comments:

Post a Comment

Java 1.7 New Features Over 1.6

Automatic Resource Management Description: A proposal to support scoping of resource usage in a block with automatic resource cleanup. T...