Creating Captcha Images Using The GD Library

I have found a random PHP script for creating captcha images using the GD Library and I've converted it to C# as promised in my previous blog post. I learned something new on this project. The first color in a new image will be the background color but only if the image is not using TrueColor.

I have to admit that this is just an idle exercise. I have no real need for this. I waste a lot of time on idle exercises, although sometimes previous research is useful later on. I think I need to be more focused on billable client work and creative work. One of the major pitfalls of intellect is that a very intelligent person is inclined to waste considerable time on pointless intellectual exercises, i.e abstractions. I think this is a trap that many IT professionals fall into because it is easy to get lost in technical details that serve no purpose. For example, how often do you find yourself struggling to install something on Linux which you are never going to use?

I have a list of some other idle exercises I was considering but I should probably focus on something else:

  1. Querying Index Server catalog using ASP.NET, maybe using LINQ. Like, why bother?
  2. Querying Active Directory using ASP.NET with LINQ. What for?
  3. Write an ASP.NET page using COBOL. This might be worthwhile if only to horrify other developers.
   1: <%@ WebHandler Language="C#" Class="CaptchaImages" %>
   2:  
   3: /*
   4: * File: CaptchaImages.ashx
   5: * Author: Simon Jarvis
   6: * Copyright: 2006 Simon Jarvis
   7: * Date: 03/08/06
   8: * Updated: 07/02/07
   9: * Requirements: PHP 4/5 with GD and FreeType libraries
  10: * Link: http://www.white-hat-web-design.co.uk/articles/php-captcha.php
  11: * 
  12: * This program is free software; you can redistribute it and/or 
  13: * modify it under the terms of the GNU General Public License 
  14: * as published by the Free Software Foundation; either version 2 
  15: * of the License, or (at your option) any later version.
  16: * 
  17: * This program is distributed in the hope that it will be useful, 
  18: * but WITHOUT ANY WARRANTY; without even the implied warranty of 
  19: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
  20: * GNU General Public License for more details: 
  21: * http://www.gnu.org/licenses/gpl.html
  22: *
  23:  * C# Version for ASP.NET
  24:  * Author: Robert S. Robbins
  25:  * Modified: 06/10/08
  26:  * Requirements: ASP.NET 2.0 with GD-Sharp
  27: */
  28:  
  29: using System;
  30: using System.Web;
  31: using System.Diagnostics;
  32: using System.Collections;
  33: using System.IO;
  34: using System.Drawing;
  35: using Ntx.GD;
  36:  
  37: public class CaptchaImages : IHttpHandler {
  38:  
  39:     private string font_file = @"C:\\WINDOWS\\Fonts\\bauhs93.ttf";
  40:     private string font_name = "Bauhaus 93";
  41:     private string mime_type = "image/jpeg";
  42:     private bool transparent_background = true;
  43:     
  44:     public void ProcessRequest (HttpContext context) {
  45:         // create trace listener file for debugging purposes
  46:         System.IO.Stream objFile = System.IO.File.Create(@"C:\Inetpub\wwwroot\study\App_Data\trace2.txt");
  47:         TextWriterTraceListener objTextListener = new TextWriterTraceListener(objFile);
  48:         Trace.Listeners.Add(objTextListener);
  49:         Trace.AutoFlush = true;
  50:  
  51:         GD image = CaptchaSecurityImage(120, 40, 6);
  52:  
  53:         /* output captcha image to browser */
  54:         context.Response.ContentType = mime_type;
  55:         MemoryStream ms = new MemoryStream();
  56:         image.Save(GD.FileType.Jpeg, ms);
  57:         byte[] binary = ms.ToArray();
  58:         context.Response.BinaryWrite(binary);
  59:         context.Response.Flush();        
  60:         
  61:         Trace.Close();
  62:         Trace.Flush();
  63:     }
  64:  
  65:     /// <summary>
  66:     /// Generates a random code with the specified number of characters.
  67:     /// </summary>
  68:     /// <param name="characters">The number of characters to generate.</param>
  69:     /// <returns>A random code.</returns>
  70:     public string generateCode(int characters) 
  71:     {
  72:         /* list all possible characters, similar looking characters and vowels have been removed */
  73:         string possible = "23456789bcdfghjkmnpqrstvwxyz";
  74:         string code = "";
  75:         int i = 0;
  76:         Random random = new Random();
  77:         while (i < characters)
  78:         {
  79:             int intRandomNumber = random.Next(0, possible.Length);
  80:             Trace.WriteLine(intRandomNumber.ToString(), "intRandomNumber");
  81:             code += possible.Substring(intRandomNumber, 1);
  82:             i++;
  83:         }
  84:         return code;
  85:     }
  86:     
  87:     public GD CaptchaSecurityImage(int width, int height, int characters)
  88:     {
  89:         string code = generateCode(characters);
  90:         /* font size will be 75% of the image height */
  91:         int font_size = Convert.ToInt32(height * 0.75);
  92:         // This is the equivalent of calling ImageCreate
  93:         GD image = new GD(width, height, false);
  94:         /* set the colours */
  95:         /* The first color in a new image should be the background color
  96:          * but it requires trueColor to be set to false*/
  97:         GDColor background_color = image.ColorAllocate(255, 255, 255);
  98:         GDColor text_color = image.ColorAllocate(20, 40, 100);
  99:         GDColor noise_color = image.ColorAllocate(100, 120, 180);
 100:         Random random = new Random();
 101:         /* generate random dots in background */
 102:         for (int i = 0; i < (width * height) / 3; i++)
 103:         {
 104:             int intRandomNumberX = random.Next(0, width);
 105:             int intRandomNumberY = random.Next(0, height);
 106:             image.FilledEllipse(intRandomNumberX, intRandomNumberY, 2, 2, noise_color);
 107:         }       
 108:         /* generate random lines in background */
 109:         for (int i = 0; i < (width * height) / 150; i++)
 110:         {
 111:             int intRandomNumberX = random.Next(0, width);
 112:             int intRandomNumberY = random.Next(0, height);
 113:             int intRandomNumberX2 = random.Next(0, width);
 114:             int intRandomNumberY2 = random.Next(0, height);
 115:             image.Line(intRandomNumberX, intRandomNumberY, intRandomNumberX2, intRandomNumberY2, noise_color);
 116:         }          
 117:         /* create textbox and add text */
 118:         int[] textbox = ImageTTFBBox(font_name, font_size, code);
 119:         // bounding rectangle
 120:         ArrayList br = new ArrayList();
 121:         br.Add(new Ntx.GD.Point(0, 0));
 122:         br.Add(new Ntx.GD.Point(textbox[0], 0));
 123:         br.Add(new Ntx.GD.Point(textbox[0], textbox[1]));
 124:         br.Add(new Ntx.GD.Point(0, textbox[1]));
 125:         /* font size will be 75% of the image height */
 126:         font_size = Convert.ToInt32(textbox[1] * 0.75);
 127:         // This is the equivalent of calling ImageTTFText
 128:         string result = image.StringFT(br, text_color, font_file, font_size, 0, 0, font_size, code, true);
 129:         Trace.WriteLine(result, "result");
 130:         
 131:         // set transparency
 132:         if (transparent_background)
 133:         {
 134:             image.ColorTransparent(background_color);
 135:         }
 136:  
 137:         return image;
 138:     }
 139:  
 140:     /// <summary>
 141:     /// Give the bounding box of a text using TrueType fonts
 142:     /// </summary>
 143:     /// <param name="font">The name of a TTF font.</param>
 144:     /// <param name="size">The size of the font.</param>
 145:     /// <param name="text">The text to be displayed using the font.</param>
 146:     /// <returns>An integer array containing the height and width.</returns>
 147:     /// <remarks>Not exactly the same as the original function, but the best we can do.</remarks>
 148:     public int[] ImageTTFBBox(string font, int size, string text)
 149:     {
 150:         Bitmap objBmpImage = new Bitmap(1, 1);
 151:  
 152:         int intWidth = 0;
 153:         int intHeight = 0;
 154:  
 155:         System.Drawing.Font objFont = new System.Drawing.Font(font, size, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Pixel);
 156:  
 157:         // Create a graphics object to measure the text’s width and height.  
 158:         Graphics objGraphics = Graphics.FromImage(objBmpImage);
 159:  
 160:         // Determine the bitmap size.  
 161:         /* Need to multiply the width by 2.0. 
 162:          * This is an ugly hack.
 163:          * The System.Drawing width will not match the GD Library drawing width.
 164:          */
 165:         intWidth = Convert.ToInt32(objGraphics.MeasureString(text, objFont).Width * 2.0);
 166:         intHeight = Convert.ToInt32(objGraphics.MeasureString(text, objFont).Height);
 167:         Trace.WriteLine(intWidth.ToString(), "intWidth");
 168:         Trace.WriteLine(intHeight.ToString(), "intHeight");
 169:         int[] box = { intWidth, intHeight };
 170:         return box;
 171:     }
 172:  
 173:     public bool IsReusable {
 174:         get {
 175:             return false;
 176:         }
 177:     }
 178:  
 179: }

3 Comments

  • Hey Robins,

    Yeah thats true man !!! Even I spend a lot of time doing things that just add to my folder named - "Code Scribbles"
    But I guess that's how we build out of the box knowledge that books & papers can't hope to propagate.
    Anyways, I'm using your code above in one of my projects (this is a billable one :) :) :) ).
    Thanx for the effort. Its a lot of help

  • like to have some exercises on creating captcha images

  • Good day! This is my first visit to your blog! We are a team of volunteers and starting a new initiative in a community in the same niche. Your blog provided us valuable information to work on. You have done a outstanding job!

Comments have been disabled for this content.