Monday, 1 July 2013

Creating Captcha using Java


In this tutorial we will see how to create Captcha using Java code and to validate through JSP. In recent days we will be seeing in most of the websites are using Captcha for security and to reduce spam entries to their website. 
Captcha is nothing but displaying text, numbers or symbols combination as an image which can not traced automatically by computers, only human can identify. In online there are lot built-in Captcha are available which can be directly included in our sites. Some will be better than other sites like it included text, voice etc.,

Here lets see simple Java code to create Captcha and to test with web application using JSP. Below are the list of files which we are going to use in this demo. 

CaptchaImage.java is a class which will generate random Captcha BufferedImage.

index.jsp used to display Captcha image and to test



CaptchaImage.java


import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;

public class CaptchaImage {

    String captchaString = "";

    // Function to generate random captcha image and returns the BufferedImage
    public BufferedImage getCaptchaImage() {
        try {
            Color backgroundColor = Color.white;
            Color borderColor = Color.black;
            Color textColor = Color.black;
            Color circleColor = new Color(190, 160, 150);
            Font textFont = new Font("Verdana", Font.BOLD, 20);
            int charsToPrint = 6;
            int width = 160;
            int height = 50;
            int circlesToDraw = 25;
            float horizMargin = 10.0f;
            double rotationRange = 0.7; 
            BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics2D g = (Graphics2D) bufferedImage.getGraphics();
            g.setColor(backgroundColor);
            g.fillRect(0, 0, width, height);

            // lets make some noisey circles
            g.setColor(circleColor);
            for (int i = 0; i < circlesToDraw; i++) {
                int L = (int) (Math.random() * height / 2.0);
                int X = (int) (Math.random() * width - L);
                int Y = (int) (Math.random() * height - L);
                g.draw3DRect(X, Y, L * 2, L * 2, true);
            }
            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
            // this should ideally be done for every language...
            // 0, O and o removed because there are confusing to users...
            // i like controlling the characters though because it helps prevent confusion
            String elegibleChars = "ABCDEFGHJKLMNPQRSTUVWXYabcdefghjkmnpqrstuvwxy23456789";
            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);

                // this is a separate canvas used for the character so that
                // we can rotate it independently
                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();
            }
            g.setColor(borderColor);
            g.drawRect(0, 0, width - 1, height - 1);
            g.dispose();
            captchaString = finalString.toString();
            System.out.println(captchaString);
            return bufferedImage;
        } catch (Exception ioe) {
            throw new RuntimeException("Unable to build image", ioe);
        }
    }

    // Function to return the Captcha string
    public String getCaptchaString() {
        return captchaString;
    }
}


index.jsp


<%@page import="javax.imageio.ImageIO"%>
<%@page import="java.io.File"%>
<%@page import="java.awt.image.BufferedImage"%>
<%@page import="com.test.CaptchaImage"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>My Captcha</title>
</head>
<body>

<%
 String result = "Invalid Entry.... :(";
 String color = "red";
    if(request.getParameter("captcha") != null && session.getAttribute("captchaStr") != null){
  if(session.getAttribute("captchaStr").equals(request.getParameter("captcha"))){
   result = "Valid Entry.... :)";
   color = "green";
  }
 }

 CaptchaImage obj = new CaptchaImage();
 BufferedImage ima = obj.getCaptchaImage();
 File outputfile = new File("c://image.jpg");
 ImageIO.write(ima, "jpg", outputfile);
 String captchaStr = obj.getCaptchaString();
 
 session.setAttribute("captchaStr", captchaStr);

%>


<form action="index.jsp" method="post">
 <table>
  <tr>
   <td><img alt="Captcha" src="c://image.jpg"/> </td>
  </tr>
  <tr>
   <td> <input type="text" value="" name="captcha"> </td>
  </tr>
  <tr>
   <td> <input type="submit" value="Submit"> </td>
  </tr>
  <tr>
   <td> <font color="<%=color%>">Value : <%= result %></font></td>
  </tr>
 </table>
</form>

</body>
</html>


OUTPUT:

Creating Captcha using Java





Creating Captcha using Java




9 comments :

  1. hi Anand,
    I found captcha image is only visible on eclipse internal browser.
    Any idea how to make captcha visible on browser like IE,Chrome,Firefox.

    ReplyDelete
  2. Hi Ashok, ru able to run jsp files through other browser ?
    If yes then this code must work since its tested and working code...

    ReplyDelete
  3. hi anand,Jsp run fine in all kind of browser generating captcha code in console everytime but showing captcha image only in eclipse internal browser.see the attachment

    ReplyDelete
  4. hi anand,jsp runing in other browser and capcha code is getting generated also but not showing image of captcha except eclipse internal browser.plz see attachments

    ReplyDelete
  5. Hi Ashok, check with different image path for saving captcha image...

    File outputfile = new File("c://image.jpg");



    instead of C:// change to some other drive and see.

    ReplyDelete
  6. which jar file i need to download to run this code??

    ReplyDelete
  7. No need of any jars except JDK. You can create dynamic web application in eclipse along with these files and directly you can through Apache Tomcat.

    ReplyDelete
  8. i am not able to run this code in net beans when i ru this code it show's no main class found

    ReplyDelete
  9. It is showing me that this package does not exist

    <%@page import="com.test.CaptchaImage"%>

    ReplyDelete