I was trying to find a solution to block spammers adding data to our database using VB.Net.
Here's a good captcha image implementation. Easy and simple.
Default.aspx
<img src="JpegImage.aspx" alt="CAPTCHA IMAGE" title="Captcha Image" style="border:1px solid #c1c1c1; width:135px; height:26px;" />
<asp:TextBox runat="server" ID="txt_captcha" MaxLength="50" Width="125" CssClass="textbox" style="margin-top:15px;"></asp:TextBox>
<asp:CustomValidator ID="valCaptcha" runat="server" ControlToValidate="txt_captcha" ValidationGroup="signupVal"
Display="Dynamic" OnServerValidate="valCaptcha_ServerValidate" CssClass="validator" ></asp:CustomValidator>
Default.aspx.vb
Protected Sub valCaptcha_ServerValidate(ByVal source As Object, ByVal args As System.Web.UI.WebControls.ServerValidateEventArgs)
If txt_captcha.Text.Trim <> Me.Session("CaptchaImageText").ToString() Then
args.IsValid = False
valCaptcha.ErrorMessage = "The security code does not match. Try again."
Else
args.IsValid = True
End If
End Sub
JpegImage.aspx // this doesn't really do anything. just for code behind.
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="JpegImage.aspx.vb" Inherits="JpegImage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Captcha Image</title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>
JpegImage.aspx.vb //You can resize image and font name here
Partial Class JpegImage
Inherits System.Web.UI.Page
Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
' Create a CAPTCHA image using the text stored in the Session object.
If IsNothing(Me.Session("CaptchaImageText")) Then
Me.Session("CaptchaImageText") = GetRandomNumber(3)
End If
Dim ci As CaptchaImage = New CaptchaImage(Me.Session("CaptchaImageText").ToString(), 135, 26, "Tahoma")
' Change the response headers to output a JPEG image.
Me.Response.Clear()
Me.Response.ContentType = "image/jpeg"
' Write the image to the response stream in JPEG format.
ci.Image.Save(Me.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg)
' Dispose of the CAPTCHA image object.
ci.Dispose()
End Sub
End Class
Function GetRandomNumber(ByVal length As Int16) As String
Dim randomM As Random = New Random()
Dim s As String = ""
For i As Integer = 0 To length
s = [String].Concat(s, randomM.[Next](10).ToString())
Next
Return s
End Function
AppCode/CapchaImage.vb
Imports System
Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Drawing.Imaging
Imports System.Drawing.Text
''' <summary>
''' Summary description for CaptchaImage
''' </summary>
Public Class CaptchaImage
'
' TODO: Add constructor logic here
'
Public Sub New()
End Sub
' Public properties (all read-only).
Public ReadOnly Property Text() As String
Get
Return Me.m_text
End Get
End Property
Public ReadOnly Property Image() As Bitmap
Get
Return Me.m_image
End Get
End Property
Public ReadOnly Property Width() As Integer
Get
Return Me.m_width
End Get
End Property
Public ReadOnly Property Height() As Integer
Get
Return Me.m_height
End Get
End Property
' Internal properties.
Private m_text As String
Private m_width As Integer
Private m_height As Integer
Private familyName As String
Private m_image As Bitmap
' For generating random numbers.
Private random As New Random()
' ====================================================================
' Initializes a new instance of the CaptchaImage class using the
' specified text, width and height.
' ====================================================================
Public Sub New(ByVal s As String, ByVal width As Integer, ByVal height As Integer)
Me.m_text = s
Me.SetDimensions(width, height)
Me.GenerateImage()
End Sub
' ====================================================================
' Initializes a new instance of the CaptchaImage class using the
' specified text, width, height and font family.
' ====================================================================
Public Sub New(ByVal s As String, ByVal width As Integer, ByVal height As Integer, ByVal familyName As String)
Me.m_text = s
Me.SetDimensions(width, height)
Me.SetFamilyName(familyName)
Me.GenerateImage()
End Sub
Protected Overrides Sub Finalize()
Try
' ====================================================================
' This member overrides Object.Finalize.
' ====================================================================
Dispose(False)
Finally
MyBase.Finalize()
End Try
End Sub
' ====================================================================
' Releases all resources used by this object.
' ====================================================================
Public Sub Dispose()
GC.SuppressFinalize(Me)
Me.Dispose(True)
End Sub
' ====================================================================
' Custom Dispose method to clean up unmanaged resources.
' ====================================================================
Protected Overridable Sub Dispose(ByVal disposing As Boolean)
If disposing Then
Me.m_image.Dispose()
' Dispose of the bitmap.
End If
End Sub
' ====================================================================
' Sets the image width and height.
' ====================================================================
Private Sub SetDimensions(ByVal width As Integer, ByVal height As Integer)
' Check the width and height.
If width <= 0 Then
Throw New ArgumentOutOfRangeException("width", width, "Argument out of range, must be greater than zero.")
End If
If height <= 0 Then
Throw New ArgumentOutOfRangeException("height", height, "Argument out of range, must be greater than zero.")
End If
Me.m_width = width
Me.m_height = height
End Sub
' ====================================================================
' Sets the font used for the image text.
' ====================================================================
Private Sub SetFamilyName(ByVal familyName As String)
' If the named font is not installed, default to a system font.
Try
Dim font As New Font(Me.familyName, 12.0F)
Me.familyName = familyName
font.Dispose()
Catch ex As Exception
Me.familyName = System.Drawing.FontFamily.GenericSerif.Name
End Try
End Sub
' ====================================================================
' Creates the bitmap image.
' ====================================================================
Private Sub GenerateImage()
' Create a new 32-bit bitmap image.
Dim bitmap As New Bitmap(Me.m_width, Me.m_height, PixelFormat.Format32bppArgb)
' Create a graphics object for drawing.
Dim g As Graphics = Graphics.FromImage(bitmap)
g.SmoothingMode = SmoothingMode.AntiAlias
Dim rect As New Rectangle(0, 0, Me.m_width, Me.m_height)
' Fill in the background.
Dim hatchBrush As New HatchBrush(HatchStyle.SmallConfetti, Color.LightGray, Color.White)
g.FillRectangle(hatchBrush, rect)
' Set up the text font.
Dim size As SizeF
Dim fontSize As Single = rect.Height + 1
Dim font As Font
' Adjust the font size until the text fits within the image.
Do
fontSize -= 1
font = New Font(Me.familyName, fontSize, FontStyle.Bold)
size = g.MeasureString(Me.m_text, font)
Loop While size.Width > rect.Width
' Set up the text format.
Dim format As New StringFormat()
format.Alignment = StringAlignment.Center
format.LineAlignment = StringAlignment.Center
' Create a path using the text and warp it randomly.
Dim path As New GraphicsPath()
path.AddString(Me.m_text, font.FontFamily, CInt(font.Style), font.Size, rect, format)
Dim v As Single = 4.0F
Dim points As PointF() = {New PointF(Me.random.[Next](rect.Width) / v, Me.random.[Next](rect.Height) / v), New PointF(rect.Width - Me.random.[Next](rect.Width) / v, Me.random.[Next](rect.Height) / v), New PointF(Me.random.[Next](rect.Width) / v, rect.Height - Me.random.[Next](rect.Height) / v), New PointF(rect.Width - Me.random.[Next](rect.Width) / v, rect.Height - Me.random.[Next](rect.Height) / v)}
Dim matrix As New Matrix()
matrix.Translate(0.0F, 0.0F)
path.Warp(points, rect, matrix, WarpMode.Perspective, 0.0F)
' Draw the text.
hatchBrush = New HatchBrush(HatchStyle.LargeConfetti, Color.LightGray, Color.DarkGray)
g.FillPath(hatchBrush, path)
' Add some random noise.
Dim m As Integer = Math.Max(rect.Width, rect.Height)
For i As Integer = 0 To CInt((rect.Width * rect.Height / 30.0F)) - 1
Dim x As Integer = Me.random.[Next](rect.Width)
Dim y As Integer = Me.random.[Next](rect.Height)
Dim w As Integer = Me.random.[Next](m / 50)
Dim h As Integer = Me.random.[Next](m / 50)
g.FillEllipse(hatchBrush, x, y, w, h)
Next
' Clean up.
font.Dispose()
hatchBrush.Dispose()
g.Dispose()
' Set the image.
Me.m_image = bitmap
End Sub
End Class