lowmanio.co.uk title image

Creating captchas in Python

Wed, 29 Jul 2009 05:10PM

Category: Programming

Written by Sarah | With 2 comments

In making this website and in my 4th year honours project I implemented a captcha (which you can see if you try and make a comment). I thought this would be a bit of a nightmare to do, but with Steven's help and the awesomeness of Python, it was quite easy. The code originally comes from here, but I have made a few edits such as keeping the image in memory.

You will need a .ttf font file to generate the image. You can specify the font size of the text, and the image generated will automatically adjust to fit in the word.

# python imports
import random
import Image
import ImageFont
import ImageDraw
import ImageFilter
from cStringIO import StringIO
from os import path
# local imports
from lowmanio.utils.utils import ROOT_DIR

 
"""
    This code is taken from and is copyright to:
    http://code.activestate.com/recipes/440588/
"""
 
FONT_FILE = path.join(ROOT_DIR, 'lowmanio', 'utils', 'arialbd.ttf')

 
def gen_captcha(text, fnt, fnt_sz, f, fmt='JPEG'):
    """Generate a captcha image"""
    
    # randomly select the foreground color
    fgcolor = random.randint(0,0xffff00)

    # make the background color the opposite of fgcolor
    bgcolor = fgcolor ^ 0xffffff
    
    # create a font object 
    font = ImageFont.truetype(fnt,fnt_sz)
    
    # determine dimensions of the text
    dim = font.getsize(text)
    
    # create a new image slightly larger that the text
    im = Image.new('RGB', (dim[0]+5,dim[1]+5), bgcolor)
    d = ImageDraw.Draw(im)
    x, y = im.size
    r = random.randint
    
    # draw 100 random colored boxes on the background
    for num in range(100):
        d.rectangle((r(0,x),r(0,y),r(0,x),r(0,y)),fill=r(0,0xffffff))

    # add the text to the image
    d.text((3,3), text, font=font, fill=fgcolor)
    im = im.filter(ImageFilter.EDGE_ENHANCE_MORE)
    
    # save the image to a file
    im.save(f, format=fmt)
 
def gen_random_word(wordLen=6):
    """Generate a random word of length wordLen. Some characters have been removed
    to avoid ambiguity such as i,l,o,I,L,0, and 1"""
 
    allowedChars = "abcdefghjkmnpqrstuvwzyzABCDEFGHJKMNPQRSTUVWZYZ23456789"
    word = ""

    for i in range(0, wordLen):
        word = word + allowedChars[random.randint(0,0xffffff) % len(allowedChars)]

    return word
 
def generateCaptcha():
    """Generate a captcha image in memory using a randomly generated word and a font 
    file on the system. Returns the word and the image"""
    
    word = gen_random_word()
    buf = StringIO()
    gen_captcha(word.strip(), FONT_FILE, 50, buf)
    s = buf.getvalue()
    buf.close()
    return word, s

When the page with the captcha is loaded, the captcha image URL controller method saves the word in the session, and returns the image to be displayed. This makes sure the images aren't cached.

Tagged with: Python, captcha

Comments

Now, the question is: do I train a MatLab program to try and break your captcha? :P
Andrew Bell
Thu, 30 Jul 2009 02:15PM
I'm sure it's not hard to break! But it serves it's purpose as a simple spam blocker :)
Sarah
Fri, 28 Aug 2009 12:31PM

Add a comment

captcha