Created
November 1, 2018 08:52
-
-
Save remones/94441a6b5e4b458aea997433c85f77de to your computer and use it in GitHub Desktop.
Captcha implement with Python
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- 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