Skip to content

Instantly share code, notes, and snippets.

@remones
Created November 1, 2018 08:52
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 remones/94441a6b5e4b458aea997433c85f77de to your computer and use it in GitHub Desktop.
Save remones/94441a6b5e4b458aea997433c85f77de to your computer and use it in GitHub Desktop.
Captcha implement with Python
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from os import path
import random
import string
from StringIO import StringIO
from PIL import Image, ImageDraw, ImageFont, ImageFilter
from flask import make_response
PATH_DIR = path.dirname(path.abspath(__file__))
class Captcha(object):
FONT_PATH = path.join(PATH_DIR, 'fonts/captcha.ttf')
LETTERS = string.ascii_letters + string.digits
def __init__(self, length=4, size=(120, 50), fontsize=36):
self.size = size
self.fontsize = fontsize
self.length = length
def _center_coords(self, draw, text, font):
width, height = draw.textsize(text, font)
xy = (self.size[0] - width) / 2.0, (self.size[1] - height) / 2.0
return xy
def _add_noise_dots(self, draw, image):
"""Add noise dots"""
size = image.size
for _ in range(int(size[0] * size[1] * 0.1)):
xy = (random.randint(0, size[0]), random.randint(0, size[1]))
draw.point(xy, fill=self._random_text_color())
return draw
def _add_noise_lines(self, draw, image):
size = image.size
line_color = self._random_bg_color()
for _ in range(3):
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=line_color, width=width)
for _ in range(2):
start = (-50, -50)
end = (size[0] + 10, random.randint(0, size[1] + 10))
draw.arc(start + end, 0, 360, fill=line_color)
return draw
def _random_text(self):
return ''.join([random.choice(self.LETTERS) for _ in range(self.length)])
def _random_color(self, range_min, range_max):
r, g, b = (random.randint(range_min, range_max) for _ in range(3))
return (r, g, b)
def _random_bg_color(self):
return self._random_color(200, 255)
def _random_text_color(self):
return self._random_color(0, 150)
def get(self):
"""generate and return captcha"""
image = Image.new("RGB", self.size, self._random_bg_color())
font = ImageFont.truetype(self.FONT_PATH, self.fontsize)
draw = ImageDraw.Draw(image)
text = self._random_text()
xy = self._center_coords(draw, text, font)
draw.text(xy=xy, text=text, font=font, fill=self._random_text_color())
# Add some dot noise
draw = self._add_noise_dots(draw, image)
# Add some random lines
draw = self._add_noise_lines(draw, image)
image = image.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大)
return image, text.lower()
def make_image_response(img, content_type='image/jpeg'):
assert isinstance(img, Image.Image)
assert content_type.split('/')[0].lower() == 'image'
img_type = content_type.split('/', 1)[1].upper()
buff = StringIO()
img.save(buff, img_type)
response = make_response(buff.getvalue())
response.headers['Content-Type'] = content_type
return response
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment