Introduciton
When developing user authentication systems, implementing a CAPTCHA (Completely Automated Public Turing test to tell Computers and Humans Apart) is an effective security measure. This article demonstrates how to create random CAPTCHA images with accompanying text using Python's Pillow library.
Required Modules
Before implementing the solution, ensure you have the necessary libraries installed:
# For generating random values
import random
# For in-memory file operations (Python 3.7+)
from io import BytesIO
# For image processing and generation
from PIL import Image, ImageDraw, ImageFont, ImageFilter
Implementation
1. Creating the CAPTCHA Generator Function
The following function generates both the CAPTCHA image and its corresponding text:
def generate_captcha(image_width=120, image_height=30, text_length=5,
font_path='Monaco.ttf', font_dimension=28):
"""
Generate a CAPTCHA image with random text.
Parameters:
- image_width: Width of the generated image
- image_height: Height of the generated image
- text_length: Number of characters in the CAPTCHA
- font_path: Path to the font file to be used
- font_dimension: Size of the font
"""
captcha_text = []
# Create a white background image
image = Image.new('RGB', (image_width, image_height), (255, 255, 255))
draw_context = ImageDraw.Draw(image, 'RGB')
def get_random_char():
"""Generate a random uppercase letter."""
return chr(random.randint(65, 90))
def get_random_color():
"""Generate a random RGB color."""
return (random.randint(0, 255),
random.randint(10, 255),
random.randint(64, 255))
# Configure font
font = ImageFont.truetype(font_path, font_dimension)
# Draw CAPTCHA text
for char_position in range(text_length):
character = get_random_char()
captcha_text.append(character)
vertical_offset = random.randint(0, 4)
horizontal_position = char_position * image_width / text_length
draw_context.text((horizontal_position, vertical_offset),
character, font=font, fill=get_random_color())
# Add noise pixels
for _ in range(40):
x = random.randint(0, image_width)
y = random.randint(0, image_height)
draw_context.point((x, y), fill=get_random_color())
# Add circular noise
for _ in range(20):
x = random.randint(0, image_width)
y = random.randint(0, image_height)
draw_context.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color())
# Add interference lines
for _ in range(5):
x1 = random.randint(0, image_width)
y1 = random.randint(0, image_height)
x2 = random.randint(0, image_width)
y2 = random.randint(0, image_height)
draw_context.line((x1, y1, x2, y2), fill=get_random_color())
# Apply edge enhancement filter
image = image.filter(ImageFilter.EDGE_ENHANCE_MORE)
return image, ''.join(captcha_text)
2. Using the CAPTCHA Generator
Here's how to utilize the function in different scenarios:
if __name__ == '__main__':
# Generate CAPTCHA
captcha_image, captcha_code = generate_captcha()
# Option 1: Display directly
# captcha_image.show()
# Option 2: Save to file
# with open('captcha.png', 'wb') as output_file:
# captcha_image.save(output_file, format='png')
# Option 3: Store in memory
memory_buffer = BytesIO()
captcha_image.save(memory_buffer, 'png')
image_bytes = memory_buffer.getvalue()
# Option 4: Python 2 compatibility
# import StringIO
# memory_buffer = StringIO.StringIO()
# captcha_image.save(memory_buffer, 'png')
# image_bytes = memory_buffer.getvalue()