zoukankan      html  css  js  c++  java
  • Django中途圖片驗證碼功能實現

    1.  图片验证码生成

      图片验证码生成,可以直接作为第三方库引用放在django项目中

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    
    
    import random
    import string
    import os.path
    from io import BytesIO
    
    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.ascii_uppercase + string.ascii_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 range(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 range(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, (text, StringIO.value).
                For example:
                    ('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)
            text = "".join(self._text)
            out = BytesIO()
            image.save(out, format=fmt)
            return text, out.getvalue()
    
        def generate_captcha(self):
            self.initialize()
            return self.captcha("")
    
    captcha = Captcha.instance()
    
    if __name__ == '__main__':
        print(captcha.generate_captcha())

    2.redis数据库设置

      在settings.py中配置redis数据库

    #redis的配置
    CACHES = {
        "default": { # 默认
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://127.0.0.1:6379/0",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
            }
        },
        "session": { # session
            "BACKEND": "django_redis.cache.RedisCache",
            "LOCATION": "redis://127.0.0.1:6379/1",
            "OPTIONS": {
                "CLIENT_CLASS": "django_redis.client.DefaultClient",
            }
        },
    }
    # session由数据库存储改为redis
    SESSION_ENGINE = "django.contrib.sessions.backends.cache"
    SESSION_CACHE_ALIAS = "session"
    
    #日志

    3.路由配置

    from django.urls import path
    from users.views import ImageCodeView
    
    urlpatterns = [
        # path的第一个参数: 路由
        # path的第二个参数: 视图函数名
        #图片验证码的路由
        path('imagecode/',ImageCodeView.as_view(),name='imagecode'),
    ]

    4.视图类

    class ImageCodeView(View):
        def get(self,request):
            uuid = request.GET.get('uuid')
            if uuid is None:
                return HttpResponseBadRequest("没有uuid")
            text,image = captcha.generate_captcha()
    
            redis_conn = get_redis_connection('default')
           #redis_conn.setex(key,timeout,value)
            redis_conn.setex('img:%s'%uuid,60,text)
            return HttpResponse(image,content_type='image/jpeg')
  • 相关阅读:
    WINDOWS REDIS 修改requirepass 不生效;
    解读JavaScript原型链
    禁止浏览器自动填写用户名密码
    Vue购物车实例
    scrollTop的兼容性
    jQuery架构(源码)分析
    web前端优化整理(转)
    前端模块化:RequireJS(转)
    前端构建之gulp与常用插件(转载)
    PS快捷键
  • 原文地址:https://www.cnblogs.com/Geirge-ye/p/13279080.html
Copyright © 2011-2022 走看看