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.