02: 自定义图片验证码插件

1.1 自定义图片验证码插件

  1、使用插件注意事项

      1、 插件代码中指定了验证码图片的字体,这里需要下载对应字体放到project中,如:project/Monaco.ttf

      2、 在使用时需要使用session功能,所以需要执行:
          python manage.py makemigrations
          python manage.py migrate

      3、 安装Pillow模块,heck_code.py(依赖:Pillow,字体文件)

      4、 src属性后面加?,实现点击验证码图片自动更新(加?号因为如果url不变浏览器不会再次发送请求)

      5、我们定义的插件可以在project下新建utils目录,将定义的插件都放到这个目录中

      6、 Monaco.ttf字体下载:https://files.cnblogs.com/files/xiaonq/Monaco.zip

  2、实现图片验证码测试文件

from app01 import views

urlpatterns = [
    url(r'^login.html$', views.login),
    url(r'^check_code.html$', views.check_code),
]
urls.py
from io import BytesIO
from django.shortcuts import HttpResponse,render
from utils.check_code import create_validate_code

def check_code(request):
    # data = open('static/imgs/avatar/20130809170025.png','rb').read()
    # return HttpResponse(data)

    # 1. 创建一张图片 pip3 install Pillow
    # 2. 在图片中写入随机字符串
    # obj = object()
    # 3. 将图片写入到指定文件
    # 4. 打开指定目录文件,读取内容
    # 5. HttpResponse(data)
    stream = BytesIO()                      #就相当于在内存中打开了一个文件
    img, code = create_validate_code()      #生成图片对象和验证码文字
    img.save(stream,'PNG')                  #生成一个图片到内存中
    request.session['CheckCode'] = code    #将生成图片放到对应用户的session中
    return HttpResponse(stream.getvalue())
    # stream.getvalue()读取出内存中生成的那张图片

def login(request):
    if request.method == 'POST':
        code = request.POST.get('check_code')   #获取前端传来的验证码图片
        if code.upper() == request.session['CheckCode'].upper():
            print('验证码正确')
        else:
            print('验证码错误')
    return render(request, 'login.html')
views.py
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <div class="login">
        <form role="form" action="/login.html" method="POST">
            <div>
            {% csrf_token %}
                <label for="password">验证码</label>

                <div>
                    <div style="float: left">
                        <input type="text" class="form-control" placeholder="请输入验证码" name="check_code">
                    </div>
                    <div style="float: left;">
                        <img src="/check_code.html" onclick="changeCheckCode(this);">
                        <!--<img src="/static/imgs/11111.jpg">-->
                    </div>
                </div>
            </div>
            <button type="submit" class="btn btn-default">登 陆</button>
        </form>
    </div>
    <script>
        function changeCheckCode(ths){
            ths.src = ths.src +  '?';
            //url没变浏览器不然重新发验证码,这里加?号就改变url了
        }
    </script>
</body>
</html>
login.html
import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter

_letter_cases = "abcdefghjkmnpqrstuvwxy"      # 小写字母,去除可能干扰的i,l,o,z
_upper_cases = _letter_cases.upper()            # 大写字母
_numbers = ''.join(map(str, range(3, 10)))      # 数字
init_chars = ''.join((_letter_cases, _upper_cases, _numbers))

def create_validate_code(size=(120, 30),
                         chars=init_chars,
                         img_type="GIF",
                         mode="RGB",
                         bg_color=(255, 255, 255),
                         fg_color=(0, 0, 255),
                         font_size=18,
                         font_type="Monaco.ttf",    #设置验证码字体
                         length=4,
                         draw_lines=True,
                         n_line=(1, 2),
                         draw_points=True,
                         point_chance=2):
    width, height = size                        # 宽高
    img = Image.new(mode, size, bg_color)       # 创建图形
    draw = ImageDraw.Draw(img)                  # 创建画笔

    def get_chars():
        """生成给定长度的字符串,返回列表格式"""
        return random.sample(chars, length)

    def create_lines():
        """绘制干扰线"""
        line_num = random.randint(*n_line)  # 干扰线条数
        for i in range(line_num):
            begin = (random.randint(0, size[0]), random.randint(0, size[1]))    # 起始点
            end = (random.randint(0, size[0]), random.randint(0, size[1]))      # 结束点
            draw.line([begin, end], fill=(0, 0, 0))

    def create_points():
        """绘制干扰点"""
        chance = min(100, max(0, int(point_chance)))            # 大小限制在[0, 100]
        for w in range(width):
            for h in range(height):
                tmp = random.randint(0, 100)
                if tmp > 100 - chance:
                    draw.point((w, h), fill=(0, 0, 0))

    def create_strs():
        """绘制验证码字符"""
        c_chars = get_chars()
        strs = ' %s ' % ' '.join(c_chars)                      # 每个字符前后以空格隔开
        font = ImageFont.truetype(font_type, font_size)
        font_width, font_height = font.getsize(strs)
        draw.text(((width - font_width) / 3, (height - font_height) / 3),strs, font=font, fill=fg_color)
        return ''.join(c_chars)
    if draw_lines:
        create_lines()
    if draw_points:
        create_points()
    strs = create_strs()
    # 图形扭曲参数
    params = [1 - float(random.randint(1, 2)) / 100,
              0,
              0,
              0,
              1 - float(random.randint(1, 10)) / 100,
              float(random.randint(1, 2)) / 500,
              0.001,
              float(random.randint(1, 2)) / 500
              ]
    img = img.transform(size, Image.PERSPECTIVE, params)    # 创建扭曲
    img = img.filter(ImageFilter.EDGE_ENHANCE_MORE)         # 滤镜,边界加强(阈值更大)
    return img, strs                                       # img就是生成的图片对象,strs是生成的文字信息
project/utils/check_code.py

   3、效果图

                   

原文地址:https://www.cnblogs.com/xiaonq/p/8016743.html