Click here to Skip to main content
13,351,044 members (66,186 online)
Click here to Skip to main content
Add your own
alternative version


15 bookmarked
Posted 4 Jan 2011

Captcha for aspx using VB.NET

, 4 Jan 2011
Rate this:
Please Sign up or sign in to vote.
Produce a captcha image for an aspx web page


To reduce the incidence of spam and reduce the likelihood of denial of service attacks, many web pages include an image block with distorted text, known as a Captcha. (There is a good article on Wikipedia at

The Code Project and other open sources have a number of code snippets for producing a captcha image on a web page. However, the majority are old and use moderately complex JavaScript and/or C#. The code in this article using Visual Basic and the increasing power available in the .NET Framework to produce significantly more complex and simple code. For example, the 30 lines needed in the past to convert binary data to base64 can now be done in a single line.

The image is drawn by obtaining a graphics object from the in memory bit map. Again the .NET framework has simplified the process of transforming the bitmap to a form that can be displayed on a webpage with the, imageformat) function to write the image to a memory stream. The memory stream is then read and converted to the required base64 string.

The captcha is not particularly sophisticated. However, it would be easy to modify the code to have, for example, smoother angle and size changes and have a more (human) attractive disruptive line across the text.

Using the Code

The code is a short class which has a method for generating a fake word and a second method for producing an in-memory bitmap with the distorted text. Having produced these, the fake word is place in a hidden text box on the page and the image is added to the page by modifying the src attribute of an <img /> tag placed on the page.

(I wish to acknowledge for the basis of the fake word generation - written in script but now translated into VB.NET. The RndInterval function could have been updated, but it was not worth doing so).

Imports System.Drawing
Public Class Captcha
Dim bmpCaptcha As Bitmap
Dim iBMPHeight As Integer = 50
Dim iBMPWidth As Integer = 220
Dim sLeftMargin As Single = 20
Dim sTopMargin As Single = 10
Dim g As Graphics
Dim sWord As String
Dim sLetter As String
Dim sfLetter As SizeF
Dim rfLetter As RectangleF
Dim sX1 As Single = 0
Dim sY1 As Single = 0
Dim sX2 As Single = 0
Dim sY2 As Single = 0
Dim sTemp As Single
Dim iAngle As Integer
Dim sOffset As Single

Public Function GenerateCaptcha(ByVal sWord As String) As Bitmap
Dim ixr As Integer
bmpCaptcha = New Bitmap(iBMPWidth, iBMPHeight, _
g = Graphics.FromImage(bmpCaptcha)
Dim drawBackground As New SolidBrush(Color.Silver)
g.FillRectangle(drawBackground, New Rectangle(0, 0, iBMPWidth, iBMPHeight))

' Create font and brush.
Dim drawFont As New Font("Times New Roman", 20)
Dim drawBrush As New SolidBrush(Color.DarkBlue)
Dim strFormat As New StringFormat(StringFormatFlags.FitBlackBox)
sfLetter = New SizeF(30, 30)
' Draw string to screen.
For ixr = 0 To sWord.Length - 1
sLetter = sWord.Substring(ixr, 1)
g = Graphics.FromImage(bmpCaptcha)
rfLetter = New RectangleF(sLeftMargin, sTopMargin, 30, 30)
sfLetter = g.MeasureString(sLetter, drawFont, sfLetter, strFormat)
iAngle = RndInterval(0, 20) - 10
With rfLetter
sOffset = sLeftMargin * Math.Tan(iAngle * Math.PI / 180)
.Y = sTopMargin - sOffset
.Width = sfLetter.Width + 10
.Height = sfLetter.Height
End With
g.DrawString(sLetter, drawFont, drawBrush, rfLetter)
sLeftMargin += sfLetter.Width + 2
Dim drawPen As Pen = New Pen(Color.Crimson, 1)
For ixr = 0 To 3
sX1 = sX2
Do While Math.Abs(sX1 - sX2) < iBMPWidth * 0.5
sX1 = RndInterval(2, iBMPWidth - 2)
sX2 = RndInterval(2, iBMPWidth - 2)
sY1 = sY2
Do While Math.Abs(sY1 - sY2) < iBMPHeight * 0.5
sY1 = RndInterval(2, iBMPHeight - 2)
sY2 = RndInterval(2, iBMPHeight - 2)
If RndInterval(0, 2) > 1 Then
sTemp = sX1
sX1 = sX2
sX2 = sTemp
End If
If RndInterval(0, 2) > 1 Then
sTemp = sY1
sY1 = sY2
sY2 = sTemp
End If

g.DrawLine(drawPen, sX1, sY1, sX2, sY2)
Return bmpCaptcha
End Function
Public Function GenerateFakeWord(ByVal iLengthRequired As Integer) As String
Dim sVowels As String = "AEIOU"
Dim sConsonants As String = "BCDFGHJKLMNPQRSTVWXYZ"
Dim iNbrVowels As Integer
Dim iNbrConsonants As Integer
Dim sWord As String
Dim bUseVowel As Boolean
Dim iWordLength As Integer
Dim sPattern As String
iNbrVowels = 0
iNbrConsonants = 0
bUseVowel = False
sWord = ""
For iWordLength = 1 To iLengthRequired
If (iWordLength = 2) Or ((iLengthRequired > 1) And (iWordLength = iLengthRequired)) Then
bUseVowel = Not bUseVowel
ElseIf (iNbrVowels < 2) And (iNbrConsonants < 2) Then
bUseVowel = ((Rnd(1) * 2) > 1)
ElseIf (iNbrVowels < 2) Then
bUseVowel = True
ElseIf (iNbrConsonants < 2) Then
bUseVowel = False
End If

sPattern = IIf(bUseVowel, sVowels, sConsonants)
sWord = sWord & sPattern.Substring(Int(Rnd(1) * sPattern.Length), 1)
If bUseVowel Then
iNbrVowels = iNbrVowels + 1
iNbrConsonants = 0
iNbrVowels = 0
iNbrConsonants = iNbrConsonants + 1
End If
Return sWord
End Function
Private Function RndInterval(ByVal iMin As Integer, ByVal iMax As Integer) As Integer
Return Int(((iMax - iMin + 1) * Rnd()) + iMin)
End Function
End Class

To use class, include something like the following three tags on the aspx page:

<body onload="onload()">

<asp:Image ID="imgCaptcha" runat="server" style="z-index: 1; left: 570px; top: 220px; 
position: absolute; width: 220px; height: 50px;" /> 

<asp:TextBox ID="txtCaptcha" runat="server" 

style="z-index: 1; left: 67px; top: 474px; position: absolute" 


And, finally, you will need some code in the aspx.vb code page to generate the captcha image and display it on the web page. The variable bOutputCaptcha can be set to output the captcha image or have the page OnLoad function do nothing and hide the image control. Typically, the page will be reloaded after the user's response which can be compared with the word which is stored in the hidden textbox, txtCaptcha. (The viewstate of aspx controls is said to be sufficiently secure that it is unlikely a computer can extract the value easily. However, the value could be left server side if you really really thought this necessary).

Private Sub ForgottenPassword_PreRender_
	(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.PreRender

        ' Example of inline base64 image tag: <img width="16" height="14" 
        ' alt="embedded folder icon" src="data:image/gif;base64,
        ' R0lGODlhEAAOALMAAOazToeHh0tLS/7LZv/0jvb29t/f3//Ub//ge8WSLf/rhf/3kdbW1mxsbP//
        ' mf///yH5BAAAAAAALAAAAAAQAA4AAARe8L1Ekyky67QZ1hLnjM5UUde0ECwLJoExKcpp
        ' V0aCcGCmTIHEIUEqjgaORCMxIC6e0CcguWw6aFjsVMkkIr7g77ZKPJjPZqIyd7sJAg
        ' VGoEGv2xsBxqNgYPj/gAwXEQA7" />

        Dim sWord As String
        Dim bmpCaptcha As Bitmap
        Dim sScript As String
        Dim sImage64 As String
        Dim iLength As Integer
        Dim iRead As Integer
        Dim msCaptcha As MemoryStream

        If bOutputCaptcha Then

              sWord = myCaptcha.GenerateFakeWord(6)
              txtCaptcha.Text = sWord

              bmpCaptcha = myCaptcha.GenerateCaptcha(sWord)

              '   The following commented out code can be used for testing
              '   It writes the image to a page by itself
             'Response.ContentType = "image/jpeg"
             'Response.AppendHeader("Content-Disposition", "inline; filename=captcha.bmp")
             'Response.CacheControl = "no-cache"
             'Response.AppendHeader("Pragma", "no-cache")
             'Response.Expires = -1
             'bmpCaptcha.Save(Response.OutputStream, Imaging.ImageFormat.Jpeg)

             msCaptcha = New MemoryStream
             bmpCaptcha.Save(msCaptcha, Imaging.ImageFormat.Jpeg)

             sImage64 = ""

             iLength = msCaptcha.Length
             Dim byteImage As Byte()

             byteImage = New Byte(CType(msCaptcha.Length, Integer)) {}

             msCaptcha.Position = 0
             iRead = msCaptcha.Read(byteImage, 0, iLength)
             sImage64 = Convert.ToBase64String(byteImage)

             sScript = vbCr + <script language="Javascript"> " vbCr

             sScript += "function onload() {" + vbCr
             sScript += "var image;" + vbCr
             sScript += "image=document.getElementById(""imgCaptcha"");" + vbCr
             sScript += "image.src='data:image/gif;base64," + sImage64 + "'"
             '   It would be possible to test for IE7 or earlier here and 
             '   put the captcha word into the alt text - but 
             '   does increase the chances of a denial of service attack 
             '   if someone figures this out
             sScript += "}" + vbCr + vbCr
             sScript+="</Script>" + vbCr

             Me.ClientScript.RegisterClientScriptBlock(Me.GetType(), quot;image", sScript)



             imgCaptcha.Visible = False
             sScript += "function onload() {" + vbCr
             sScript += "}" + vbCr + vbCr
             sScript+="</Script>" + vbCr

             Me.ClientScript.RegisterClientScriptBlock(Me.GetType(), "image", sScript)

        End If

    End Sub

Note the little bit of code that is commented out - it is possible to save the bitmap directly to the http response stream and display the image alone on the page for testing purposes.

The user will need to have scripting permitted on their browser.

The image uses the inline URI for image display. The image is encoded in base64 (i.e. 7 bit characters). This means the image is typically 30% larger than the original bit map (which in this example is typically about 3KB).

Not all browsers will display inline base64 images - most importantly Internet Explorer 7 and earlier will not display them. Internet Explorer 8 and later will display the images and have a limited of 32KB. Firefox and Safari are said to have done so for much longer, but many are limited to 4KB images. The bitmap images produced here are typically 3KB so that even after the conversion to base64 should be able to be displayed.

(I hope the script is accurately translated. The CodeProject web page thought it was malicious code and removed everything between the <script></script> tags - so I could not copy it directly and had to type the code between separately!!)


  • No changes have been made to the code at this stage (Jan 2011).





About the Author

John Faris
Software Developer
Australia Australia
No Biography provided

You may also be interested in...


Comments and Discussions

Generalnice - have 5 Pin
Pranay Rana4-Jan-11 19:58
memberPranay Rana4-Jan-11 19:58 



Permalink | Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.180111.1 | Last Updated 4 Jan 2011
Article Copyright 2011 by John Faris
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid