Skip to content

Instantly share code, notes, and snippets.

@yxy
Created October 9, 2015 04:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save yxy/c65f0477d8b545bfce26 to your computer and use it in GitHub Desktop.
Save yxy/c65f0477d8b545bfce26 to your computer and use it in GitHub Desktop.
A simple captcha generator using PIL
#-*- encoding: utf8 -*-
from PIL import Image, ImageDraw, ImageFont
import random
import string
class SimpleCaptchaException(Exception):
pass
class SimpleCaptcha(object):
def __init__(self, length=5, size=(100, 100), fontsize=36,
random_text=None, random_bgcolor=None):
self.text = "CAPTCHA"
self.bgcolor = 255
self.size = size
self.fontsize = fontsize
self.length = length
self.image = None # current captcha image
if random_text:
self.text = self._random_text()
if not self.text:
raise SimpleCaptchaException("Field text must not be empty.")
if not self.size:
raise SimpleCaptchaException("Size must not be empty")
if not self.fontsize:
raise SimpleCaptchaException("Fontsize must be defined")
if random_bgcolor:
self.bgcolor = self._random_color()
def _center_coords(self, draw, font):
width, height = draw.textsize(self.text, font)
xy = (self.size[0] - width) / 2., (self.size[1] - height) / 2.
return xy
def _add_noise_dots(self, draw):
"""Add noise dots"""
size = self.image.size
for _ in range(int(size[0] * size[1] * .1)):
xy = (random.randint(0, size[0]), random.randint(0, size[1]))
draw.point(xy, fill="white")
return draw
def _add_noise_lines(self, draw):
size = self.image.size
for _ in range(8):
width = random.randint(1, 2)
start = (0, random.randint(0, size[1] - 1))
end = (size[0], random.randint(0, size[1] - 1))
draw.line([start, end], fill="white", width=width)
for _ in range(8):
start = (-50, -50)
end = (size[0] + 10, random.randint(0, size[1] + 10))
draw.arc(start + end, 0, 360, fill="white")
return draw
def get_captcha(self, size=None, text=None, bgcolor=None):
if text is not None:
self.text = text
if size is not None:
self.size = size
if bgcolor is not None:
self.bgcolor = bgcolor
self.image = Image.new("RGB", self.size, self.bgcolor)
font_path = "/Library/Fonts/Tahoma.ttf"
font = ImageFont.truetype(font_path, self.fontsize)
draw = ImageDraw.Draw(self.image)
xy = self._center_coords(draw, font)
draw.text(xy=xy, text=self.text, font=font)
# Add some dot noise
draw = self._add_noise_dots(draw)
# Add some random lines
draw = self._add_noise_lines(draw)
self.image.show()
return self.image, self.text
def _random_text(self):
letters = string.ascii_lowercase + string.ascii_uppercase
random_text = ""
for _ in range(self.length):
random_text += random.choice(letters)
return random_text
def _random_color(self):
r = random.randint(0, 255)
g = random.randint(0, 255)
b = random.randint(0, 255)
return (r, g, b)
if __name__ == "__main__":
sc = SimpleCaptcha(length=7, fontsize=20, random_text=True,
random_bgcolor=True)
print sc.get_captcha()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment