Click here to Skip to main content
Click here to Skip to main content

CAPTCHA Image

By , 9 Feb 2004
 

Sample Image - CaptchaImage.gif

Introduction

CAPTCHA stands for "completely automated public Turing test to tell computers and humans apart." What it means is, a program that can tell humans from machines using some type of generated test. A test most people can easily pass but a computer program cannot.

You've probably encountered such tests when signing up for an online email or forum account. The form might include an image of distorted text, like that seen above, which you are required to type into a text field.

The idea is to prevent spammers from using web bots to automatically post form data in order to create email accounts (for sending spam) or to submit feedback comments or guestbook entries containing spam messages. The text in the image is usually distorted to prevent the use of OCR (optical character reader) software to defeat the process. Hotmail, PayPal, Yahoo and a number of blog sites have employed this technique.

This article demonstrates how to create such an image and employ it within an ASP.NET web form.

Background

You can find more information on CAPTCHA at The CAPTCHA Project and read about its use in foiling purveyors of pills, pr0n and pyramid-schemes in an article from Scientific American entitled Baffling the Bots.

Before using this technique however, you should consider how it will affect your site's accessibility to the blind and other visually impaired visitors. PayPal attempts to address this problem on their sign up form by including a link to an audio file, in which a voice spells out the image text.

The code presented here produces only an image. But, if you had code to generate an audio file, you could easily integrate it.

Using the code

The source code zip file contains the source for one class and two web forms. To use it, just create a new web project and add those items.

Files

  • CaptchaImage.cs - defines the CapchaImage object which actually creates the image.
  • Default.aspx, Default.aspx.cs - a sample web form.
  • JpegImage.aspx, JpegImage.aspx.cs - a web form designed to output a JPEG image rather than HTML.

Let's look at each component and it's purpose.

CaptchaImage.cs

The CaptchaImage object creates an image given parameters for the text to be displayed, the image dimensions and, optionally, the font to use.

The heart of the code is the GenerateImage() method, shown below, which creates a bitmap image of the specified width and height. This method is called from the CaptchaImage constructor, so the image is ready as soon as you create a new instance of the object.

To create the image, we first fill in the background using a hatched brush (the "dirtier" the image appears, the harder it is for an OCR program to read it).

To make the text fit within the image, we start with an initial font size based on the image height and use the Graphics.MeasureString() method to find the resulting dimensions of the drawn text. If the text exceeds the image dimensions, we reduce the font size and test again and again until a suitable font size is found.

    // ====================================================================
    // Creates the bitmap image.
    // ====================================================================
    private void GenerateImage()
    {
      // Create a new 32-bit bitmap image.
      Bitmap bitmap = new Bitmap(
        this.width,
        this.height,
        PixelFormat.Format32bppArgb);

      // Create a graphics object for drawing.
      Graphics g = Graphics.FromImage(bitmap);
      g.SmoothingMode = SmoothingMode.AntiAlias;
      Rectangle rect = new Rectangle(0, 0, this.width, this.height);

      // Fill in the background.
      HatchBrush hatchBrush = new HatchBrush(
        HatchStyle.SmallConfetti,
        Color.LightGray,
        Color.White);
      g.FillRectangle(hatchBrush, rect);

      // Set up the text font.
      SizeF size;
      float fontSize = rect.Height + 1;
      Font font;
      // Adjust the font size until the text fits within the image.
      do
      {
        fontSize--;
        font = new Font(
          this.familyName,
          fontSize,
          FontStyle.Bold);
        size = g.MeasureString(this.text, font);
      } while (size.Width > rect.Width);

      // Set up the text format.
      StringFormat format = new StringFormat();
      format.Alignment = StringAlignment.Center;
      format.LineAlignment = StringAlignment.Center;

      // Create a path using the text and warp it randomly.
      GraphicsPath path = new GraphicsPath();
      path.AddString(
        this.text,
        font.FontFamily,
        (int) font.Style,
        font.Size, rect,
        format);
      float v = 4F;
      PointF[] points =
      {
        new PointF(
          this.random.Next(rect.Width) / v,
          this.random.Next(rect.Height) / v),
        new PointF(
          rect.Width - this.random.Next(rect.Width) / v,
          this.random.Next(rect.Height) / v),
        new PointF(
          this.random.Next(rect.Width) / v,
          rect.Height - this.random.Next(rect.Height) / v),
        new PointF(
          rect.Width - this.random.Next(rect.Width) / v,
          rect.Height - this.random.Next(rect.Height) / v)
      };
      Matrix matrix = new Matrix();
      matrix.Translate(0F, 0F);
      path.Warp(points, rect, matrix, WarpMode.Perspective, 0F);

      // Draw the text.
      hatchBrush = new HatchBrush(
        HatchStyle.LargeConfetti,
        Color.LightGray,
        Color.DarkGray);
      g.FillPath(hatchBrush, path);

      // Add some random noise.
      int m = Math.Max(rect.Width, rect.Height);
      for (int i = 0; i < (int) (rect.Width * rect.Height / 30F); i++)
      {
        int x = this.random.Next(rect.Width);
        int y = this.random.Next(rect.Height);
        int w = this.random.Next(m / 50);
        int h = this.random.Next(m / 50);
        g.FillEllipse(hatchBrush, x, y, w, h);
      }

      // Clean up.
      font.Dispose();
      hatchBrush.Dispose();
      g.Dispose();

      // Set the image.
      this.image = bitmap;
    }

Once the font is set, we define a GraphicsPath() which essentially converts the text to a set of lines and curves. This can then be distorted using the GraphicsPath.Warp() method with some randomly generated values. The effect is similar to holding a cardboard sign up by opposite corners and giving it a bit of a twist. The resulting path is drawn onto the image, again using a hatch brush to give it a "dirty" appearance.

To complete the distortion, small blots are randomly painted over the image. You could experiment with other effect to thwart OCRs, but keep in mind that it should still be legible to humans, some of whom may have visual impairments

Default.aspx

This is a very simple sample web form that contains only a few basic elements, namely an <IMG> tag for the image, a text box and a "Submit" button.

    <form id="Default" method="post" runat="server">
      <img src="JpegImage.aspx"><br>
      <p>
        <strong>Enter the code shown above:</strong><br>
        <asp:TextBox id="CodeNumberTextBox" runat="server"></asp:TextBox>
        <asp:Button id="SubmitButton" runat="server" Text="Submit">
        </asp:Button><br>
      </p>
      <p>
        <em class="notice">
          (Note: If you cannot read the numbers in the above<br>
          image, reload the page to generate a new one.)</em>
      </p>
      <p><asp:Label id="MessageLabel" runat="server"></asp:Label></p>
    </form>

Note that the SRC attribute of the <IMG> tag points to the web form JpegImage.aspx.

The code-behind for Default.aspx simply generates a random text string for the image and validates that this text was entered by the user when the form is submitted. The key is to store the text string in the Session object.

    private void Page_Load(object sender, System.EventArgs e)
    {
      if (!this.IsPostBack)

        // Create a random code and store it in the Session object.
        this.Session["CaptchaImageText"] = GenerateRandomCode();

      else
      {
        // On a postback, check the user input.
        if (this.CodeNumberTextBox.Text ==
          this.Session["CaptchaImageText"].ToString())
        {
          // Display an informational message.
          this.MessageLabel.CssClass = "info";
          this.MessageLabel.Text = "Correct!";
        }
        else
        {
          // Display an error message.
          this.MessageLabel.CssClass = "error";
          this.MessageLabel.Text = "ERROR: Incorrect, try again.";

          // Clear the input and create a new random code.
          this.CodeNumberTextBox.Text = "";
          this.Session["CaptchaImageText"] = GenerateRandomCode();
        }
      }
    }

The reason for storing the text string in the Session object is so that it can be accessed by JpegImage.aspx.

JpegImage.aspx

For this web form, no HTML is needed (what's there is just the default code generated by Visual Studio when the file was created). Instead of HTML, the code will produce a JPEG image.

In the code-behind, we first create a CaptchaImage object, using the text retrieved from the Session object. This creates a bitmap image for us.

    private void Page_Load(object sender, System.EventArgs e)
    {
      // Create a CAPTCHA image using the text stored in the Session object.
      CaptchaImage ci = new CaptchaImage(
        this.Session["CaptchaImageText"].ToString(),
        200, 50, "Century Schoolbook");

      // Change the response headers to output a JPEG image.
      this.Response.Clear();
      this.Response.ContentType = "image/jpeg";

      // Write the image to the response stream in JPEG format.
      ci.Image.Save(this.Response.OutputStream, ImageFormat.Jpeg);

      // Dispose of the CAPTCHA image object.
      ci.Dispose();
    }

We then modify the HTTP response headers to set the Content-type to "image/jpeg" so the client browser will know we are sending an image.

The last step is to retrieve the bitmap image from CaptchaImage.Image and write it to the HTTP response output stream in JPEG format. Fortunately, the Save() method of the Bitmap object makes this simple. Any other supported image format could be used as well so long as the Content-type header is set accordingly.

Points of Interest

Because the CaptchaImage class contains a Bitmap object, and bitmaps employ unmanaged resources, a custom Dispose() method is implemented. This allows those unmanaged resources to be freed whenever a CaptchaImage is destroyed.

History

January 26, 2004 - version 1.0

  • Initial version.

February 2, 2004 - version 1.01

  • Minor fix to correct parameter checking in CaptchaImage.SetDimensions().

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

BrainJar
Web Developer
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionParser Error in Vs 2010memberRaj.Rautela16 Mar '13 - 2:07 
In VS 2010, it shows parser error:
Server Error in '/CaptchaImage' Application.
Parser Error
Description: An error occurred during the parsing of a resource required to service this request. Please review the following specific parse error details and modify your source file appropriately.
 
Parser Error Message: Could not load type 'CaptchaImage._Default'.
 
Source Error:
 

Line 1:  <%@ Page language="c#" Codebehind="Default.aspx.cs" AutoEventWireup="false" Inherits="CaptchaImage._Default" %>
Line 2:  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
Line 3:  <HTML>
 

Source File: /CaptchaImage/Default.aspx    Line: 1
 
Version Information: Microsoft .NET Framework Version:4.0.30319; ASP.NET Version:4.0.30319.1

Questionlicense [modified]membersprixxx28 Jan '13 - 0:36 
I wanna use part captcha this in technical school project, what is license, because i can't find any messages about it in files

modified 28 Jan '13 - 6:57.

GeneralMy vote of 5memberarashtixawd28 Dec '12 - 1:55 
it was so useful for me, thank you ...
good luclk
QuestionCaptcha is noy displaying in OS Windows XPmemberAdepto30 Sep '12 - 14:31 
Hi BrainJar , do you happen to know why your code works fine in Windows seven but not in Windows XP, I have installed Framework 4. The captcha is not displaying properly. It breaks at Bitmap.Save method showing
QuestionIt does not work in Android, helpmemberjuanjosei24 Sep '12 - 6:32 
The random generator works fine, the session save the right value but alwasy display the same immage in a mobile Android, any suggestions?
Questionimage not displayed when published in IIS7memberMember 944762721 Sep '12 - 3:17 
image not displayed when published in IIS7
QuestionCan't see the imagemembermishkaPishka2 Sep '12 - 1:16 
Hello,
Maybe I'm missing something.. the "CaptchaImageText" is what?
 
I have to create a DB?
 
I cant see the images.
 
Please help/
 
Thanks.
GeneralAwesome!!!!memberMichael Valverde27 Jun '12 - 9:58 
This worked great for me! Thanks!!!!!! Smile | :)
Michael Valverde
--------------------
Software Engineer

QuestionIssue in website implementationmembersmartboy78619 Jun '12 - 0:44 
Hi BrainJar,
 
I am not able to implement this in website. I mean it's working fine when i have added the code to New Project, but when i have selected new asp.net website instead of New Project it's creating issues..Please tell me how to resolve this..
 
Thanks,
GeneralMy Vote of 5memberAngsuman Chakraborty29 Nov '11 - 20:53 
Hi Brain,
Thanks it was help full. Just looking to edit your code to generate coloured font.
 
Thanks
QuestionTesting of captcha codememberMember 843700327 Nov '11 - 1:39 
It give me error as <%@ Page language="c#" Codebehind="Default.aspx.cs" AutoEventWireup="false" Inherits="CaptchaImage._Default" %> thn what i have to do next to solve this problem?????
pls give me solution of this problem..
AnswerRe: Testing of captcha codemembermneale121 Dec '11 - 7:38 
I have had the same problem using this in .Net 4.0 VS 2010. Without a fix this code is worthless. Will be looking to see how to make this work and will post more after I find a solution if I do.
Brother Miles

AnswerRe: Testing of captcha codemembermneale121 Dec '11 - 8:42 
Took a few minutes but the fix is rather easy. When you create your first project that you will move the objects into from the zip file, call that project Captcha. If you do not all the internal wireing the author put into the code will not connect properly and you will have to rewire it all yourself.
 
FYI - Once you have it working you might change the code to generate a better string to include inthe captcha having only numbers in the string leaves the door open for a cracker to cut in rather quickly dependino on the length of the string.
 
Otherwise nice piece of code once you have it running. THANKS! Blush | :O Blush | :O
Brother Miles

Questionhaving problems creating captcha databasememberPhakamile8819 Oct '11 - 8:01 
hai i need to know how to create a database and put some words that ithem to be displayed when running the captcha image.i am not a programmer can you please make every thing clear for me
 
thanks
Questioncapchamemberlincolngovindsamy27 Sep '11 - 23:34 
this code works like a charm. can you tell me how i change the numbers to alphabets? so i can put 2 words
QuestionUse handler instead of web formmemberJ.-C. Gauthier20 Aug '11 - 17:42 
I would suggest using a HTTP handler (ashx) instead of a web form (aspx) to generate the jpg image.
 
You can access the session state with the following interfaces BaseHttpHandler, IRequiresSessionState.
 
Supposely, there is less useless events generated with a handler.
=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
JC Gauthier - http://www.grandmenhir.com/

QuestionToday crackedmemberasapinfo1 Aug '11 - 23:45 
After some years... spammers are able to post messages catching the right code... there is an upgrade of c# class CaptchaImage?
Its nice and i don't want to use external web services...
Thank you for your kind attention!
GeneralMy vote of 5mvpMd. Marufuzzaman25 Jul '11 - 9:48 
Excellent
Generalcaptcha image with databasemembernanba903 Apr '11 - 2:49 
hi!!
i've run this coding, its great..i just want to know how to make
the same captcha but replace the random number with my own words
from database.i really hope you can help me.thnx in advance.
GeneralRe: captcha image with databasemvpJohn Simmons / outlaw programmer3 Apr '11 - 3:02 
You're missing the point of using a captcha image. In order to maintain its randomness, it MUST be recreated every time it's needed.
".45 ACP - because shooting twice is just silly" - JSOP, 2010
-----
You can never have too much ammo - unless you're swimming, or on fire. - JSOP, 2010
-----
"Why don't you tie a kerosene-soaked rag around your ankles so the ants won't climb up and eat your candy ass." - Dale Earnhardt, 1997

GeneralRe: captcha image with databasemembernanba903 Apr '11 - 6:29 
yes i know that but i need to build captcha with words for my assignment.
GeneralMy vote of 5memberharsha narayana3 Apr '11 - 2:09 
awesome Smile | :)
GeneralthanksmemberMember 766514711 Feb '11 - 1:53 
thanks for giving this code.
it is very useful for my project.
best online casinos
GeneralImage not showingmemberaeganfox10 Feb '11 - 23:33 
Hi I am not able to see the image. i just see the blank control even after setting the src location.
GeneralRe: Image not showingmemberShaniboy2629 Aug '12 - 15:31 
yah..there's no image of the captcha itself..only a broken logo?? how can we supposed to try it if it is working or not?? Sigh | :sigh:
GeneralMy vote of 4membersyscom02861 Feb '11 - 23:04 
code not working but may be my fault.
GeneralImage not showingmemberRoyaltyming22 Nov '10 - 17:26 
I've applied the codings and accordingly but the image does not show up.
GeneralRe: Image not showingmemberShaniboy2629 Aug '12 - 15:31 
yah.. the image doesn't show up. Sigh | :sigh:
Generalnot working on remote servermemberniravsahayata23 Sep '10 - 6:07 
hi..
its really a nice post..i have use this code for my application,it is working properly for
localhost,but when i have uploaded this code to web server its give me session regarding   error
whats the solution?
thanks
GeneralRe: not working on remote servermemberRumbly30 Sep '10 - 4:23 
What happens when you run it? Are you getting error messages? What are the error messages?
QuestionHow I got it to work in VS 2008memberRumbly22 Jun '10 - 3:25 
Put file CaptchaImage.cs into "App_Code" folder.
 
In file CaptchaImage.cs change the line "namespace CaptchaImage" to "namespace Captcha".
 
In file Default.aspx line 1 change Inherits="CaptchaImage._Default" to Inherits="Captcha._Default".
 
In file Default.aspx.cs comment out the following lines ....
protected System.Web.UI.WebControls.TextBox CodeNumberTextBox;
protected System.Web.UI.WebControls.Button SubmitButton;
protected System.Web.UI.WebControls.Label MessageLabel;
 
In file JpegImage.aspx line 1 change Inherits="CaptchaImage.JpegImage" to Inherits="Captcha.JpegImage".
 
In file JpegImage.aspx change the form id to anything else e.g. <form id="form1" method="post" runat="server">
 

I've put a zip file up containing modified c# code at http://www.lanzarote-villa.net/catchpafiles/Catchpa_cs.zip. Enjoy & feel free to book a holiday while you are there Big Grin | :-D

I dont know what I want, but I want it now!!! - Sir Henry Rawlinson

AnswerRe: How I got it to work in VS 2008membersyscom02862 Feb '11 - 0:09 
Dear frnd,
code developed by you works toooooooo gud.
 
thanks
dhiraj Big Grin | :-D
GeneralRe: How I got it to work in VS 2008memberRumbly18 Mar '11 - 5:48 
You are very welcome, glad it was of use to you Cool | :cool:
Generaldo not workmembernitin modi26 May '10 - 17:35 
GenerateRandomCode() does not exists..... this is occuring........
GeneralGreate Postmemberkartikps_19799 Feb '10 - 11:08 
It's help me lots... Thanks
GeneralGreat post!memberpspboyster11 Jan '10 - 6:48 
Thanks for taking your time on creating this tutorial! The C# code works perfectly for me. I was considering using ReCaptcha, but couldn't manage to customize it to our liking. This code is much easier to implement within our site.
GeneralGood example!!memberjmfigueroa11 Jan '10 - 4:06 
BrainJar,
Thanks you very much for this simple, easy and effective example!
 
Greetings from argentina
 
Juan Manuel Figueroa Bailon
GeneralI am Still getting this error . 'JpegImage': member names cannot be the same as their enclosing typememberPankaj_tiwari198829 Dec '09 - 0:56 
Plz suggest me solution for this. I modified both pages as told in previous posts but still i am getting this same error message.
 
I need your support...
Generalerror using the codememberuser198011 Dec '09 - 6:09 
hello,
 
can somebody please help me. I am getting the error:
The type or namespace name 'CaptchaImage' could not be found (are you missing a using directive or an assembly reference?)	
when I am using the code in my webapplication. My web application name is WebApplication1 and hence the namespace is WebApplication1 too. Where should I change the namepsace or any directive. I did create a new folder app_code and put the CaptchaImage.cs in it.also did change the code in .aspx files (inherits="WebApplication1.")
Any help wuld be greatly appreciated. thanks in advnace.
GeneralRe: error using the codememberAlpaslan Yolcu19 Oct '10 - 6:36 
Should be an App_code Asp directory error. I faced the same error. But after I add asp.directory App_code and put the ChaptaImage.cs below, it worked for me! Maybe you got the same! I use VC2010
GeneralTOP TIPmemberajingar1 Dec '09 - 4:42 
I finally got it working, but make sure you create a folder in your website project called App_Code, and then place the Captchaimage.cs file in there.
 
It works then. (I'm obviously a novice as well)
QuestionWhich version of VS is this aimed for?memberajingar1 Dec '09 - 3:08 
Hi,
 
Is this code aimed for VS2005 or 2008?
 
As wether to use "codebehind" or "codefile" is quite important.
 
Thanks, Ashok
GeneralGreat job!memberRobPipkin18 Nov '09 - 9:12 
Simple and tidy. Works for simple sites that likely won't be a target for bots. good job.
-Rob
General[My vote of 2] Needed workmemberwarbman14 Nov '09 - 15:30 
The code is a great starting point. However, it required quite a bit of debugging and enhancement with AJAX to get a reasonable look-n-feel.
GeneralUpdated code in CS and VB [modified]memberMurryGammash7 Nov '09 - 6:05 
I modified the code to make it work in VS2008 2.0 both in VB and C#.
download Links:
 
VB: http://www.gammash.org/files/captcha_vb.zip
C#: http://www.gammash.org/files/captcha_cs.zip
 
Murry Gammash
 
modified on Saturday, November 7, 2009 1:23 PM

GeneralRe: Updated code in CS and VBmemberajingar1 Dec '09 - 4:07 
This works fine - Thank you!
 
Ashok
QuestionLicense for CAPTCHA Image?memberDean Sauer2 Nov '09 - 4:35 
Hello,
 
Please let me know which license the source files for CAPTCHA Image are licensed under.
 
Regards,
-Dean
GeneralCaptchamembermmilitar30 Oct '09 - 13:19 
Does anyone know a good captcha control woith sound?
 
Weight loss
GeneralCAPTCHA Image without the need for JpegImagememberOperation105327 Sep '09 - 22:49 
change the line in Default.aspx
from:
<img src="JpegImage.aspx">
to:
<asp:Image ID="Image1" runat="server" />
 
In the Default.aspx.vb (onload event) after the folowing lines:

' Create a random code and store it in the Session object.
Session("CaptchaImageText") = GenerateRandomCode()

 
Add the following lines:

Dim ci As CaptchaImage.CaptchaImage = New CaptchaImage.CaptchaImage(Session("CaptchaImageText"), 200, 50, "Century Schoolbook")
ci.image.Save(Server.MapPath("generated_image.jpg"), ImageFormat.Jpeg)
ci.Dispose()
Image1.ImageUrl = "generated_image.jpg"

 

 
Or in C# in the Default.aspx.cs (onload event) after the folowing lines:

// Create a random code and store it in the Session object.
this.Session["CaptchaImageText"] = GenerateRandomCode();

 
Add the following lines:

CaptchaImage ci = new CaptchaImage(this.Session["CaptchaImageText"].ToString(), 200, 50, "Century Schoolbook");
// Write the image to the response stream in JPEG format.
ci.Image.Save(Server.MapPath("generated_image.jpg"), ImageFormat.Jpeg);
 
// Dispose of the CAPTCHA image object.
ci.Dispose();
Image1.ImageUrl = "generated_image.jpg";

 
Now you can remove all references to the JpegImage files.
 
PS: This will also allow you to debug the CaptchaImage code.
GeneralRe: CAPTCHA Image without the need for JpegImage [modified]memberNetDave2 Oct '09 - 20:01 
As much as I hate writing temp files, this is a lot easier to grok. Thanks for your suggestion!
 
[edit]Well, I just found this: CAPTCHA Server Control[^]. Kind of makes this one moot. But still, any CP article is a GREAT article.[/edit]
 
QRZ? de WAØTTN
modified on Saturday, October 3, 2009 11:40 AM

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130516.1 | Last Updated 10 Feb 2004
Article Copyright 2004 by BrainJar
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid