• flask 登录验证码 字母和数字


    captcha.py

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-

    # refer to `https://bitbucket.org/akorn/wheezy.captcha`

    import random
    import string
    import os.path
    from cStringIO import StringIO

    from PIL import Image
    from PIL import ImageFilter
    from PIL.ImageDraw import Draw
    from PIL.ImageFont import truetype


    class Bezier:
    def __init__(self):
    self.tsequence = tuple([t / 20.0 for t in range(21)])
    self.beziers = {}

    def pascal_row(self, n):
    """ Returns n-th row of Pascal's triangle
    """
    result = [1]
    x, numerator = 1, n
    for denominator in range(1, n // 2 + 1):
    x *= numerator
    x /= denominator
    result.append(x)
    numerator -= 1
    if n & 1 == 0:
    result.extend(reversed(result[:-1]))
    else:
    result.extend(reversed(result))
    return result

    def make_bezier(self, n):
    """ Bezier curves:
    http://en.wikipedia.org/wiki/B%C3%A9zier_curve#Generalization
    """
    try:
    return self.beziers[n]
    except KeyError:
    combinations = self.pascal_row(n - 1)
    result = []
    for t in self.tsequence:
    tpowers = (t ** i for i in range(n))
    upowers = ((1 - t) ** i for i in range(n - 1, -1, -1))
    coefs = [c * a * b for c, a, b in zip(combinations,
    tpowers, upowers)]
    result.append(coefs)
    self.beziers[n] = result
    return result


    class Captcha(object):
    def __init__(self):
    self._bezier = Bezier()
    self._dir = os.path.dirname(__file__)
    # self._captcha_path = os.path.join(self._dir, '..', 'static', 'captcha')

    @staticmethod
    def instance():
    if not hasattr(Captcha, "_instance"):
    Captcha._instance = Captcha()
    return Captcha._instance

    def initialize(self, width=200, height=75, color=None, text=None, fonts=None):
    # self.image = Image.new('RGB', (width, height), (255, 255, 255))
    self._text = text if text else random.sample(string.uppercase + string.uppercase + '3456789', 4)
    self.fonts = fonts if fonts else
    [os.path.join(self._dir, 'fonts', font) for font in ['Arial.ttf', 'Georgia.ttf', 'actionj.ttf']]
    self.width = width
    self.height = height
    self._color = color if color else self.random_color(0, 200, random.randint(220, 255))

    @staticmethod
    def random_color(start, end, opacity=None):
    red = random.randint(start, end)
    green = random.randint(start, end)
    blue = random.randint(start, end)
    if opacity is None:
    return red, green, blue
    return red, green, blue, opacity

    # draw image

    def background(self, image):
    Draw(image).rectangle([(0, 0), image.size], fill=self.random_color(238, 255))
    return image

    @staticmethod
    def smooth(image):
    return image.filter(ImageFilter.SMOOTH)

    def curve(self, image, width=4, number=6, color=None):
    dx, height = image.size
    dx /= number
    path = [(dx * i, random.randint(0, height))
    for i in xrange(1, number)]
    bcoefs = self._bezier.make_bezier(number - 1)
    points = []
    for coefs in bcoefs:
    points.append(tuple(sum([coef * p for coef, p in zip(coefs, ps)])
    for ps in zip(*path)))
    Draw(image).line(points, fill=color if color else self._color, width=width)
    return image

    def noise(self, image, number=50, level=2, color=None):
    width, height = image.size
    dx = width / 10
    width -= dx
    dy = height / 10
    height -= dy
    draw = Draw(image)
    for i in xrange(number):
    x = int(random.uniform(dx, width))
    y = int(random.uniform(dy, height))
    draw.line(((x, y), (x + level, y)), fill=color if color else self._color, width=level)
    return image

    def text(self, image, fonts, font_sizes=None, drawings=None, squeeze_factor=0.75, color=None):
    color = color if color else self._color
    fonts = tuple([truetype(name, size)
    for name in fonts
    for size in font_sizes or (65, 70, 75)])
    draw = Draw(image)
    char_images = []
    for c in self._text:
    font = random.choice(fonts)
    c_width, c_height = draw.textsize(c, font=font)
    char_image = Image.new('RGB', (c_width, c_height), (0, 0, 0))
    char_draw = Draw(char_image)
    char_draw.text((0, 0), c, font=font, fill=color)
    char_image = char_image.crop(char_image.getbbox())
    for drawing in drawings:
    d = getattr(self, drawing)
    char_image = d(char_image)
    char_images.append(char_image)
    width, height = image.size
    offset = int((width - sum(int(i.size[0] * squeeze_factor)
    for i in char_images[:-1]) -
    char_images[-1].size[0]) / 2)
    for char_image in char_images:
    c_width, c_height = char_image.size
    mask = char_image.convert('L').point(lambda i: i * 1.97)
    image.paste(char_image,
    (offset, int((height - c_height) / 2)),
    mask)
    offset += int(c_width * squeeze_factor)
    return image

    # draw text
    @staticmethod
    def warp(image, dx_factor=0.27, dy_factor=0.21):
    width, height = image.size
    dx = width * dx_factor
    dy = height * dy_factor
    x1 = int(random.uniform(-dx, dx))
    y1 = int(random.uniform(-dy, dy))
    x2 = int(random.uniform(-dx, dx))
    y2 = int(random.uniform(-dy, dy))
    image2 = Image.new('RGB',
    (width + abs(x1) + abs(x2),
    height + abs(y1) + abs(y2)))
    image2.paste(image, (abs(x1), abs(y1)))
    width2, height2 = image2.size
    return image2.transform(
    (width, height), Image.QUAD,
    (x1, y1,
    -x1, height2 - y2,
    width2 + x2, height2 + y2,
    width2 - x2, -y1))

    @staticmethod
    def offset(image, dx_factor=0.1, dy_factor=0.2):
    width, height = image.size
    dx = int(random.random() * width * dx_factor)
    dy = int(random.random() * height * dy_factor)
    image2 = Image.new('RGB', (width + dx, height + dy))
    image2.paste(image, (dx, dy))
    return image2

    @staticmethod
    def rotate(image, angle=25):
    return image.rotate(
    random.uniform(-angle, angle), Image.BILINEAR, expand=1)

    def captcha(self, path=None, fmt='JPEG'):
    """Create a captcha.

    Args:
    path: save path, default None.
    fmt: image format, PNG / JPEG.
    Returns:
    A tuple, (name, text, StringIO.value).
    For example:
    ('fXZJN4AFxHGoU5mIlcsdOypa', 'JGW9', 'x89PNG x1a x00x00x00 ...')

    """
    image = Image.new('RGB', (self.width, self.height), (255, 255, 255))
    image = self.background(image)
    image = self.text(image, self.fonts, drawings=['warp', 'rotate', 'offset'])
    image = self.curve(image)
    image = self.noise(image)
    image = self.smooth(image)
    name = "".join(random.sample(string.lowercase + string.uppercase + '3456789', 24))
    text = "".join(self._text)
    out = StringIO()
    image.save(out, format=fmt)
    if path:
    image.save(os.path.join(path, name), fmt)
    return name, text, out.getvalue()

    def generate_captcha(self):
    self.initialize()
    return self.captcha("")

    captcha = Captcha.instance()


    if __name__ == '__main__':
    print captcha.generate_captcha()

    validate_picture.py

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    from . import auth_code_blueprint as authcode
    from utils.captcha.captcha import captcha
    from flask import make_response, session
    from flask import request

    @authcode.route('/validate_picture', methods=['GET', 'POST'])
    def validate_picture():
    name, text, image_data = captcha.generate_captcha()
    text = text.lower()

    session[text] = text  #后台使用session保存

    response = make_response(image_data)
    response.headers['Content-Type'] = 'image/jpg'
    return response

  • 相关阅读:
    1069. Prufer Code 夜
    CROCMBTU 2012, Elimination Round (ACMICPC) D. Restoring Table 夜
    CROCMBTU 2012, Elimination Round (ACMICPC) H. Queries for Number of Palindromes 夜
    1145. Rope in the Labyrinth 夜
    1721. Two Sides of the Same Coin 夜
    1182. Team Them Up! 夜
    1162. Currency Exchange 夜
    1056. Computer Net 夜
    FOJ 2013 A short problem
    Codeforces 11.23
  • 原文地址:https://www.cnblogs.com/Adalia-Ting/p/10033466.html
Copyright © 2020-2023  润新知