Sunday, February 5, 2012

How to convert an image to bytes in .NET?

One of the most standard queries I come across in many of the coding forums these days is, how do we convert an image (Image/Bitmap class) in .NET to a byte[] array? The answer to this is very straight forward - a few lines of code in VB.NET or C#:


VB.NET:


        Private Function CaptureScreen() As Bitmap
            'CAPTURE THE BITMAP
            ' Size size is how big an area to capture
            ' pointOrigin is the upper left corner of the area to capture
            Dim width As Integer =  Screen.PrimaryScreen.Bounds.X + Screen.PrimaryScreen.Bounds.Width
            Dim height As Integer =  Screen.PrimaryScreen.Bounds.Y + Screen.PrimaryScreen.Bounds.Height
            Dim size As Size =  New Size(width,height)
            Dim pointOfOrigin As Point =  New Point(0,0)
            Dim desktopBitmap As Bitmap =  New Bitmap(size.Width,size.Height)
            Imports (Graphics graphics = Graphics.FromImage(desktopBitmap))
            {
                graphics.CopyFromScreen(pointOfOrigin,New Point(0,0),size)
            }
            'CAPTURE CURSOR
            Dim cursorX As Integer = 0,cursorY As Integer =  0
            Dim cursorBitmap As Bitmap =  CaptureCursor( cursorX,ref cursorY)
            'MERGE THE CURSOR INTO DESKTOP BITMAP
            If Not cursorBitmap Is Nothing Then
                Dim g As Graphics
                Dim r As Rectangle
                r = New Rectangle(cursorX, cursorY, cursorBitmap.Width, cursorBitmap.Height)
                g = Graphics.FromImage(desktopBitmap)
                g.DrawImage(cursorBitmap, r)
                g.Flush()
                Return desktopBitmap
            Else
                Return desktopBitmap
            End If
        End Function


C#: 


        private Bitmap CaptureScreen()
        {
            //CAPTURE THE BITMAP
            // Size size is how big an area to capture
            // pointOrigin is the upper left corner of the area to capture
            int width = Screen.PrimaryScreen.Bounds.X + Screen.PrimaryScreen.Bounds.Width;
            int height = Screen.PrimaryScreen.Bounds.Y + Screen.PrimaryScreen.Bounds.Height;
            Size size = new Size(width, height);
            Point pointOfOrigin = new Point(0, 0);
            Bitmap desktopBitmap = new Bitmap(size.Width, size.Height);
            using (Graphics graphics = Graphics.FromImage(desktopBitmap))
            {
                graphics.CopyFromScreen(pointOfOrigin, new Point(0, 0), size);
            }
            //CAPTURE CURSOR
            int cursorX=0, cursorY=0;
            Bitmap cursorBitmap = CaptureCursor(ref cursorX,ref cursorY);
            //MERGE THE CURSOR INTO DESKTOP BITMAP
            if (cursorBitmap != null)
            {
                Graphics g;
                Rectangle r;
                r = new Rectangle(cursorX, cursorY, cursorBitmap.Width, cursorBitmap.Height);
                g = Graphics.FromImage(desktopBitmap);
                g.DrawImage(cursorBitmap, r);
                g.Flush();
                return desktopBitmap;
            }
            else
            {
                return desktopBitmap;
            }
        }




Do note that the parameter passed to this function should be an object of System.Drawing.Bitmap type. If you have an object of Image type instead, you may convert it to Bitmap by doing this:


Graphics.FromImage(imageObject)

Tuesday, January 17, 2012

How to code efficiently in a .NET language?

Here are some techniques you may apply in your quest to become a better .NET coder:


[1] Follow proper naming conventions for variables and constants. A good naming convention has several advantages such as providing meta-data about the variable or function name, promotes consistency and readability within a team and provides better understanding in case of code-reuse.

For variables and type names, Microsoft recommends a pascal casing convention where the first letter of the name is capitalized and the rest is in proper case (example "ToString", "Red", "BackColor", "ForeColor", etc.). For parameter names, Microsoft recommends camel casing convention where the first letter of the name is small and the rest is proper case (example "toString", "red", "backColor", "foreColor", etc.)

Microsoft also has recommendations for naming Assemblies & DLLs,  Namespaces, Struct Types, etc. For more information on this, see Microsoft .NET Design guidelines for class libraries

[2] Always keep possible code-reuse in mind while coding. While coding, it is always a good practice to consider the effect of exposing your functionality to other users in the form of a Library/API. Instead of scavenging for bugs later, you will save lots of time and concentration by planning ahead for it.
It is also a good practice to avoid possible formatting of data while returning values from your functions or sub-procedures, and leave those implementation details to the caller instead.

[3] Clean up your unused and local variables. This is the number one efficient factor that directly affects the performance of your code. Always keep a habit of releasing the memory used by local variables in the Finally block. Also, release all .NET and COM Global/Module-level variables when they are no longer needed.
In order to clear COM objects, you have to call Marshal.ReleaseCOMObject() function explicitly, whereas .NET objects will be released by just setting them to null (C#) or Nothing (VB.NET).

[4] Avoid using GoTo statements. There is nothing inherently wrong with using Goto statements in VB.NET, but they reduce the code-readability. Its easy to lose track of the issue at hand, while scavenging for the possible effects by following your Goto statements.

[5] Always use FxCop to audit your code. FxCop is a free tool from Microsoft that checks your assembly for compliance with Microsoft Design guidelines. Apart from highlighting inconsistencies in issues like naming-conventions, an important advantage of using FxCop is that it brings to light several performance improvizations that could be made to your code. Here is the download page for FxCop version 10.0:

FxCop download page.

Saturday, August 6, 2011

How to perform Cross-thread communication in .NET programs

Multithreading is a quite useful technique in programming, especially in complex applications that seem to do a lot of things at the same time. The System.Threading class in .NET provides members that allow us to seamlessly create, stop and abort threads at will. But this article is not about managing threads, there are already several texts available for that. This is about managing a very typical scenario that is faced by a developer working on a multi threaded application.

Quite recently, while developing a network application and using multiple threads, I came across this very problem. The program was basically a TCP Message Server that accepted TCP and UDP requests on the network and replied to them with some processed data. We had one main GUI that acts as the user interface for the server. Now, at the click of a start button, there are two different threads that need to start: a TCPListener and a UDPListener thread. So now, we had three threads:-
  1. The main GUI thread started by the user.
  2. TCPListener thread listening for TCP requests on a port.
  3. UDPListener thread listening for UDP requests on a different port.
Here are some parts of the implementation:
GUI: Basic Server GUI with a Start/Stop button and a text box for last message received.

Saturday, July 30, 2011

How to create an FTP client in VB.NET

The FTP (File Transfer Protocol) is one of the oldest and most popular ways of transferring files from one computer to another over a TCP network such as the internet. It is a Client/Server based protocol based on cear-text authentication. To get a detailed idea of what FTP is and how it is used, refer to http://en.wikipedia.org/wiki/File_Transfer_Protocol

In .NET,  we implement the FTP functionality using the System.Net namespace. This is a comprehensive namespace which encapsulates functionality to perform various network tasks. These include FTP related tasks like connecting to an FTP server and listing its directory.

In this article, we will learn how to create an FTP Client using the VB.NET language right from scratch.

The IDE I have used is Visual Studio 2008, though you can easily port it to the 2010 version. The complete source-code for this solution is available on Google Code. You can download it here:
 
http://code.google.com/p/ftpexplorer/downloads/detail?name=ftpexplorer_source_1.zip

You can also translate it to C# (with a little bit of effort) since all .NET languages share the same FCL and CLI. There is a C# equivalent for each syntax.

To begin, create a VB solution of the type “Windows Forms Application”. Add a Form to it, then add the below controls to the Form:

  1. A TreeView control – to browse the local file system
  2. A ListView control – to browse the remote ftp structure
  3. A TextBox and a Button to type Url and connect to the FTP server
  4. Two Upload and Download buttons
  5. A multi-line TextBox for logging details
  6. A StatusStrip control with a label on it (Optional)
This will be your FTP client interface where you can do things like connecting to a remote ftp site using your username and password and start uploading/downloading files. The appearance is quite minimalist, and I have abstained from adding many advanced functions like using an SSL connection and applying cryptography, so as not to overwhelm the learners. Here is our little FTP Explorer in action:




The Upload button uploads the selected file on the local system to the remote directory that is currently selected. Similarly, selecting a file on the remote system and clicking the download button downloads the file to the selected local folder.

On the remote system, double-clicking a folder will navigate to that folder. The big multi-line textbox is for logging the ftp events.

On the coding front, I have abstracted the core FTP related functionality in a different class called FtpClient, so that the functionality could be reused or exposed through an API.

The local-system's explorer-tree on the top left side is just filled with the drive letters in the beginning. Later, as the user starts expanding the nodes, they are populated with the sub-folders and files.

Private Sub tvwLocal_AfterExpand(ByVal sender As Object, ByVal e As System.Windows.Forms.TreeViewEventArgs) Handles tvwLocal.AfterExpand
On Error GoTo em
Dim current As TreeNode = e.Node
'Dim nextFile As String = Dir(current.Name & "\", FileAttribute.Directory)
Dim dirInfo As String() = Directory.GetDirectories(current.Name & "\")
current.Nodes.Clear()
'Do While (nextFile IsNot Nothing AndAlso nextFile.Length > 0)
For Each nextFile As String In dirInfo
Dim dirnode As New TreeNode
dirnode.Text = ExtractFileName(nextFile)
dirnode.Name = nextFile ' current.Name & "\" & nextFile
dirnode.ImageIndex = Images.CLOSED_FOLDER
dirnode.SelectedImageIndex = Images.CLOSED_FOLDER
dirnode.Nodes.Add("*DUMMY*")
'current.Nodes.Add(current.Name & "\" & nextFile, nextFile, Images.CLOSED_FOLDER, Images.CLOSED_FOLDER)
current.Nodes.Add(dirnode)
'Loop
Next
dirInfo = Directory.GetFiles(current.Name & "\")
'nextFile = Dir(current.Name & "\")
For Each nextFile As String In dirInfo
current.Nodes.Add(nextFile, ExtractFileName(nextFile), Images.FILE, Images.FILE)
Next
Exit Sub
em:
If Err.Number <> 52 And Err.Number <> 57 Then
MessageBox.Show(Err.Description)
End If
End Sub

As for the FTP handling, the class constructor takes three arguments: the FTP host, username and password. The most important method in this class is the ListDirectory(). This function sends a LIST request to the remote ftp server and gets the directory and files listing in the form of an ftp-string. It then creates an object of FtpDirectory class which is basically a generic list of FtpFileInfo objects. FtpFileInfo is an important object that reads the ftp-string using regular expressions and categorizes them into a file or a folder.




Public Function ListDirectory(Optional ByVal directory As String = "") As FtpDirectory
On Error GoTo em
Dim url As String
If directory.Length = 0 Then
Me.CurrentDirectory = "/"
'url = Hostname
ElseIf directory = "." Then
'No need to do anything
ElseIf directory = ".." Then
If CurrentDirectory <> "/" Then
'/pub/a
Dim index As Integer = Me.CurrentDirectory.LastIndexOf("/")
CurrentDirectory = CurrentDirectory.Substring(0, index)
If CurrentDirectory.Length = 0 Then CurrentDirectory = "/"
Else
RaiseEvent StatusChanged("Already in the root directory")
'url = Hostname & "/" & CurrentDirectory
End If
Else
Me.CurrentDirectory &= IIf(CurrentDirectory.Length = 1, "", "/") & directory
End If
url = GetCurrentUrl()
RaiseEvent StatusChanged("Logging in with user " & Username)
'return a simple list of filenames in directory
Dim ftp As Net.FtpWebRequest = GetRequest(url)

'Set request to do simple list

ftp.Method = Net.WebRequestMethods.Ftp.ListDirectoryDetails
Dim response As FtpWebResponse = ftp.GetResponse()
Dim sr As New StreamReader(response.GetResponseStream())
Dim str As String = sr.ReadToEnd()
'replace CRLF to CR, remove last instance
str = str.Replace(vbCrLf, vbCr).TrimEnd(Chr(13))
'split the string into a list
If Not Authenticated Then
Authenticated = True
RaiseEvent StatusChanged(response.WelcomeMessage)
RaiseEvent StatusChanged("Login successful...")
End If
RaiseEvent StatusChanged("Current directory is " & CurrentDirectory)
Return New FtpDirectory(str, url)
Exit Function
em:
MessageBox.Show(Err.Description)
End Function


The regular expressions are matched based on six different unix directory listing patterns that are most commonly used.



Public Enum DirectoryEntryTypes
File
Directory
End Enum

Sub New(ByVal line As String, ByVal path As String)
'parse line
Dim m As Match = GetMatchingRegex(line)
If m Is Nothing Then
'failed
Throw New ApplicationException("Unable to parse line: " & line)
Else
Me.FileName = m.Groups("name").Value
Me.Path = path
Me.Size = CLng(m.Groups("size").Value)
Me.Permission = m.Groups("permission").Value
Dim _dir As String = m.Groups("dir").Value
If (_dir <> "" And _dir <> "-") Then
Me.FileType = DirectoryEntryTypes.Directory
Else
Me.FileType = DirectoryEntryTypes.File
End If

Try
Me.FileDateTime = Date.Parse(m.Groups("timestamp").Value)
Catch ex As Exception
Me.FileDateTime = Nothing
End Try
End If
End Sub




Private Function GetMatchingRegex(ByVal line As String) As Match
Dim formats As String() = { _
                    "(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\w+\s+\w+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{4})\s+(?<name>.+)", _
                    "(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\d+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{4})\s+(?<name>.+)", _
                    "(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\d+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{1,2}:\d{2})\s+(?<name>.+)", _
                    "(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})\s+\d+\s+\w+\s+\w+\s+(?<size>\d+)\s+(?<timestamp>\w+\s+\d+\s+\d{1,2}:\d{2})\s+(?<name>.+)", _
                    "(?<dir>[\-d])(?<permission>([\-r][\-w][\-xs]){3})(\s+)(?<size>(\d+))(\s+)(?<ctbit>(\w+\s\w+))(\s+)(?<size2>(\d+))\s+(?<timestamp>\w+\s+\d+\s+\d{2}:\d{2})\s+(?<name>.+)", _
                    "(?<timestamp>\d{2}\-\d{2}\-\d{2}\s+\d{2}:\d{2}[Aa|Pp][mM])\s+(?<dir>\<\w+\>){0,1}(?<size>\d+){0,1}\s+(?<name>.+)"}Dim rx As Regex, m As Match
For i As Integer = 0 To formats.Length - 1
rx = New Regex(formats(i)) 
m = rx.Match(line) 
If m.Success Then 
Return m 
End If 
Next 
End Function
















For connecting to the remote ftp server, we use the FtpWebRequest class provided by the .NET framework class library through the System.Net namespace. The StatusChange() event of the FtpClient is used to get notifications in the main form where we can display or log this status on a multi-line text-box.

Private Sub client_StatusChanged(ByVal newStatus As String) Handles client.StatusChanged
txtLog.AppendText(newStatus &amp; Environment.NewLine)
Application.DoEvents()
End Sub

The client object's ListDirectory() function is again called when the list view item is double-clicked or an upload is complete

Private Sub ListRemoteDirectory(ByVal directory As String)
lvwRemote.Items.Clear()
'Request = CType(FtpWebRequest.Create(txtUrl.Text), FtpWebRequest)
'Request.Credentials = New NetworkCredential(cred(0), cred(1))
RemoteDir = client.ListDirectory(directory)
LastDirectory = directory
lvwRemote.Items.Add("..", "..")
For Each item As FtpFileInfo In RemoteDir
If item.FileType = FtpFileInfo.DirectoryEntryTypes.Directory Then
lvwRemote.Items.Add(item.FileName, Images.CLOSED_FOLDER)
Else
lvwRemote.Items.Add(item.FileName, Images.FILE)
End If
Next

End Sub

Private Sub lvwRemote_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles lvwRemote.DoubleClick
If lvwRemote.SelectedItems.Count = 0 Then
Dim item As ListViewItem = lvwRemote.SelectedItems(0)
If item.ImageIndex = Images.FILE Then
ListRemoteDirectory(item.Text)
End If
End If
End Sub

The remaining tricks of the trade can be easily understood once you go through the code. For any doubts or queries please contact me.

Sunday, July 17, 2011

Network programming in VB.NET and C#

The .NET framework provides an extensive set of functions to enable network programming using the objects in System.Net and System.Net.Socket namespaces. Let us look into some basic network concepts that we need to develop, say a chat program or a remote-signaling application in .NET.

[1] Sockets and Ports:

Socket is the communication agent on the physical network layer. When your computer talks to another one, socket is like a virtual device on your system that sends and receives the TCP packets. Port is like a channel on which packets relating to a specific program are being sent or received. When your program is listening for data on port number 2051, no other program can. In .NET framework, a socket is represented by the object System.Net.Sockets.Socket. However, the object TcpListener can also be used as an alternative to the Socket for listening to TCP packets.

[2] Addresses and Endpoints:

In order to talk to a remote computer, we need to know its IP-address. This is represented by System.Net.IPAddress. It contains special members to get some vital information. For eg, the IPAddress.Loopback gives the local loop-back address to communicate with the local host. This is usually 127.0.0.1.
An end-point is a combination of an ip-address and a port. As mentioned earlier, we need these two information about a remote computer to communicate with its listening socket. This is System.Net.IPEndpoint.

[3] The Dns namespace:

The namespace System.Dns is very important in .net. Without it you would be crippled to do even basic tasks like resolving a computer's host name to its ip-address. Below are some key static functions of this object:

Dns.GetHostEntry() - Resolves a given name or address to a specific host (returns IPHostEntry).

Dns.GetHostName() - Returns name of a host computer.

Dns.GetHostAddresses() - Returns all ip-addresses of a given host-name or ip-address.



Let us now look at some common network tasks to perform in VB.net or C#:

[1] Finding any computer's ip address: You can easily get the host-name given its ip-address by the GetHostEntry(), but how will you find the ip-address given its name? Here you have to check the array of addresses returned by the GetHostName(), as done in the below c# function that you can add in your class:

public IPAddress GetAddressFromHost(string hostName)
{
//IPAddress address = Dns.GetHostEntry(txtRemoteHost.Text).AddressList[0];
IPHostEntry host = Dns.GetHostEntry(hostName);
IPAddress[] addresses = Dns.GetHostAddresses(host.HostName);
IPAddress address;
if (addresses[0].ToString() == "127.0.0.1" && addresses.Length > 1)
{
address = addresses[1];
}
else
{
address = addresses[0];
}
return address;
}


[2] Sending a tcp message to another computer. All you need to know is the remote computer's host-name or ip-address and the port number on which it is listening to. You will have to make use of the Stream object to write your message:

public void SendMessage(string remoteHost, int remotePort, string command, string body)
{
try
{
//string hostName = Dns.GetHostEntry(remoteClient.EndPoint.Address).HostName;
string localHostName = Dns.GetHostEntry("localhost").HostName;
TcpClient client = new TcpClient(remoteHost,remotePort);
//TcpClient client = new TcpClient();
Stream s = client.GetStream();
StreamWriter sw = new StreamWriter(s);
sw.AutoFlush = true;
sw.Write(localHostName + "#" + PortNo.ToString() + "#" + ServerName + "#" + command + "#" + body);
sw.Close();
s.Close();
client.Close();
}
catch
{
}
}

Sunday, February 27, 2011

How to develop CAPTCHA functionality in ASP.NET

Ever wondered after seeing those little curvy digits in neat boxes followed by input saying “Enter the above text:”. This usually happens when you register for a free online service like an email-id or FTP service. Such validation may also happen before you submit any comment on a blog or website. You might wonder, after all what is the point of this?

CAPTCHA in ASP.NET
CAPTCHA in ASP.NET


The idea is to incorporate a validation to protect from spam and stop internet bots from automatically submitting forms on your website. CAPTCHA stands for “Completely Automated Public Turing Test To Tell Computers and Humans Apart”.

Computers have automated most of the tasks that humans do on the net, and creating a program to impersonate a human by filling some text-boxes on a HTML form is a very simple task in a language like Java, VB.net or C#. Such programs are called auto-bots or internet-bots that are usually used by spammers.
Bots are also used to manipulate results of online-polls. For instance, in November 1999, Slashdot released an online poll asking which was the best graduate school to study computer science. IP addresses of voters were recorded in order to prevent single users from voting more than once. However, students at Carnegie Mellon found a way to stuff the ballots using programs that voted for CMU thousands of times. CMU's score started growing rapidly. The next day, students at MIT wrote their own program and the poll became a contest between voting bots. MIT finished with 21,156 votes, Carnegie Mellon with 21,032 and every other school with less than 1,000!

Can the result of any online poll be trusted? Not unless the poll ensures that only humans can vote. And that can be done by using CAPTCHA. It is not necessary that CAPTCHA should be a manual image verification. It could even be a common sense question like “What is the capital of India?” or “What is one plus one?”.
Such simple questions for humans are still a challenge for most AI programs, and it is very difficult to write a generic bot to create such a complex task that involves natural language processing. However, if somebody is specifically targeting your website, this question can be easily bypassed as the answer will be “Delhi” each time the form is submitted.
Moreover, for a small website, it is difficult to come up with a dictionary of so many questions and switch between them randomly. Ultimately each one will be deciphered after several attempts by the bot.
The only full-proof solution is image based verification. Reading curved letters is one of the few tasks done on a computer, in which even the present best technology cannot beat the cortex. Consider the below image:

CAPTCHA in ASP.NET

Reading the above image involves three tasks (from a computer’s point of view):
1. Pre-processing: Removing the background clutter and noise.
2. Segmentation: Splitting the image into regions which contain a single character.
3. Classification: Identifying the character in each region.
In fact, tasks 1 and 3 are pretty easy for a computer. This is being done since ages through a technology called OCR (Optical Character Recognition). Only the task 2, of differentiating each character still remains a challenge for even the most advanced AI programs. On the other hand, it is a piece of cake, for even the most dumbest of humans.

Now, let us get down to the technical task of creating such a random image, and verifying the same in ASP.net. Assuming that you know the basics of ASP.net like developing web-forms, code-behind pages, handling session variables, etc. I’ll start with the particulars of creating this functionality. The language I’m using is c-sharp, but VB.net alternatives also exist for those who are interested. The .net framework being used in the example is 2.0 and development tool is Visual Studio 2005.
Basically, we need one web-form (.aspx) and one class (.cs) file to develop this functionality. Although, you can merge both into one, I suggest you keep the bitmap-creation part in the class, while rendering the output to the browser using .aspx. Apart from these two, there will be a third web-form that uses the CAPTCHA functionality. This will typically be a login page or a comment page on the blog.

CaptchaImage.cs:


public int height = 0;
    public int width = 0;
    public string familyname = "Verdana";
    public string text="";
    public Bitmap image;

    private Random random = new Random();

    public void dispose()
    {
        image = null;
        random = null;
 }
    public void GenerateImage()
    {
        Bitmap bt = new Bitmap(this.width,this.height,System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        
        //Create the graphics object
        Graphics g = Graphics.FromImage(bt);
        g.SmoothingMode = SmoothingMode.AntiAlias;
        Rectangle rect = new Rectangle(0, 0, this.width, this.height);

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

        //Text font
        SizeF size;
        float fontsize = rect.Height + 1;
        Font font;

        //Adjust the text size until the text fits within the image
        do
        {
            fontsize--;
            font = new Font(
            this.familyname,
            fontsize,
            FontStyle.Bold
                );
            size = g.MeasureString(text,font);
        } while (size.Width > rect.Width);

        //Text format
        StringFormat format = new StringFormat();
        format.Alignment = StringAlignment.Center;
        format.LineAlignment = StringAlignment.Center;

        //Create text path & warp it randomly
        GraphicsPath path = new GraphicsPath();
        path.AddString(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(this.width- this.random.Next(rect.Width)/v,this.height- this.random.Next(rect.Height)/v)
        };
        Matrix matrix = new Matrix();
        matrix.Translate(0F, 0F);
        path.Warp(points, rect, matrix,WarpMode.Perspective,0F);

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

        //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(hb, x, y, w, h);
        }
        
        //Clean up
        font.Dispose();
        hb.Dispose();
        g.Dispose();

        //set image
        this.image = bt;
    }




Above code is the heart of your CAPTCHA functionality. Input is provided to this object using public variables like height, width and text. A graphics object is used to create the bitmap. Hatch brush is used to first fill the background, and later draw the text. The curved appearance to the end result is given by the warp() method of the graphics path, and also by the style of the Hatch brush.

Default.aspx.cs:


protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
            Session["CaptchaText"] = GenerateRandomCode();
        }
    }
    protected void Button1_Click(object sender, EventArgs e)
    {
        if (TextBox1.Text == Session["CaptchaText"].ToString())
        {
            Label1.Text = "Validation successful";
        }
        else 
        {
            Label1.Text = "Incorrect Captcha";
            Session["CaptchaText"] = GenerateRandomCode();
        }
    }
    public static string GenerateRandomCode()
    {
        char c = (char)0; int dice = 0;
        string res = "";
        for (int i = 0; i <= 3; i++)
        {
            dice = random.Next(2,2);
            switch (dice)
            {
                case 1: //A
                    c = (char)random.Next(65, 90);
                    break;
                case 2: //a
                    c = (char)random.Next(97, 122);
                    break;
                case 3: //1
                    c = (char)random.Next(48, 57);
                    break;
            }

            res += c.ToString();
        }

        return res;
    }



This will be your login or comment web-form that uses the CAPTCHA functionality. In the code-behind file, you need to generate a random Captcha and store in a session variable in the page-load. Here, it is important to check that generation is done only if it is not a PostBack, else it is a case of validating existing Captcha posted by the user.


Default.aspx:



<asp:Image ID="Image1" runat="server" ImageUrl="~/Views/Home/CaptchaJPEG.aspx" /><br />
    <br />
    <asp:TextBox ID="TextBox1" runat="server"></asp:TextBox><br />
    <asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Submit" /><br />
    <br />
    <asp:Label ID="Label1" runat="server"></asp:Label>


In Default.aspx i.e. the Front-end part, we just take normal image control. Instead of assigning its ImageUrl property to a .jpg/.gif, we assign it to an .aspx page, CaptchaJPEG.aspx. This web-form will do rendering the bitmap part. It will call the CaptchaImage class’s GenerateImage() function to generate the bitmap using the text from the session variable.

CaptchaJPEG.aspx.cs:


CaptchaImage captcha = new CaptchaImage();
    protected void Page_Load(object sender, EventArgs e)
    {
        captcha.width = 250;//200;
        captcha.height = 50;//50;
        captcha.text = this.Session["CaptchaText"].ToString();
        captcha.GenerateImage();

        captcha.image.Save(this.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
    }



Once you hook up the above things correctly, all you have to do is start your Default.aspx in a web browser. If everything goes right, you will see a nice piece of CAPTCHA validation functionality as seen below:

CAPTCHA in ASP.NET

Thursday, December 25, 2008

Erl - A unique feature in Visual Basic 6

Erl is probably one of the least known features in VB6. There is a very strong possibility that you have never even heard its name. I stumbled upon it a few months back while trying to get something on error handling mechanisms in VB6.

Remember a unique feature about the old procedural languages like C++, BASIC or PASCAL? They provided a very important statistic about the error that occurred in the program. Apart from the error number and description, they provided the line number on which the error occurred. This feature later became quite extinct in the later 4th generation languages like Foxpro. However Visual-Basic, the popular successor of the BASIC language maintained this compatibility. However, it was not very well documented or much popular.

This feature in VB6 is called Erl. In fact, Erl is a special variable name in VB6. This variable contains the line-number where the error occurred. However, there is a small price to pay in order to use this variable. It requires that we label each line number as we used to do it in old BASIC language. But that is only inside the procedure where “on error resume” statement is used. I tried this thing by creating a new Standard-Exe project. Then, added one blank form and a new command-button. Inside the button, I added the following code:

Private Sub Command1_Click()
1: On Error GoTo em
2: Dim val1 As Integer
3: Dim val2 As Integer
4: Dim result As Integer
5: val1 = 20
6: val2 = 0
7: result = val1 / val2
8: Exit Sub
em:
MsgBox "Error occured on line " & Erl & ": " & Err.Description
End Sub


As you can see, I’ve deliberately created an error on line number 7 by dividing 20 by zero. And guess what? The error message displayed contains the line number 7 when I run the program!

If you omit the labeling for each statement, Erl variable would contain zero.

I also created my own variable Erl inside the above procedure just out of curiosity. In that case, my new variable over-rides the system variable Erl and it would behave as just another ordinary variable.

Meanwhile, I’ve tried to do the same thing in VB.NET. i.e. displaying the error-number. I haven’t found a way to do so yet. MS has also removed this built-in Erl variable. If you have got any suggestions, then do shoot them.

To give me feedback or shoot any queries, use the comments link on this page.