天天看點

繪制圖檔驗證碼, 并在前端使用

生成并發送圖檔驗證碼

1. 安裝包

python繪圖需要安裝

pillow

pip install pillow
           

2. 繪圖源代碼

(57行, 裡面的字型需要自己下載下傳和修改)

import random
import string
# Image:一個畫布
# ImageDraw:一個畫筆
# ImageFont:畫筆的字型
from PIL import Image,ImageDraw,ImageFont
# pip install pillow

# Captcha驗證碼

class Captcha(object):
    # 生成幾位數的驗證碼
    number = 4
    # 驗證碼圖檔的寬度和高度
    size = (100,30)
    # 驗證碼字型大小
    fontsize = 25
    # 加入幹擾線的條數
    line_number = 2

    # 建構一個驗證碼源文本
    SOURCE = list(string.ascii_letters)
    for index in range(0, 10):
        SOURCE.append(str(index))


    #用來繪制幹擾線
    @classmethod
    def __gene_line(cls,draw,width,height):
        begin = (random.randint(0, width), random.randint(0, height))
        end = (random.randint(0, width), random.randint(0, height))
        draw.line([begin, end], fill = cls.__gene_random_color(),width=2)


    # 用來繪制幹擾點
    @classmethod
    def __gene_points(cls,draw,point_chance,width,height):
        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=cls.__gene_random_color())


    # 生成随機的顔色
    @classmethod
    def __gene_random_color(cls,start=0,end=255):
        random.seed()
        return (random.randint(start,end),random.randint(start,end),random.randint(start,end))


    # 随機選擇一個字型
    @classmethod
    def __gene_random_font(cls):
        # 這裡的字型可以自己做響應的修改
        fonts = [
            'verdana.ttf'
        ]
        font = random.choice(fonts)
        return 'utils/captcha/'+font


    # 用來随機生成一個字元串(包括英文和數字)
    @classmethod
    def gene_text(cls, number):
        # number是生成驗證碼的位數
        return ''.join(random.sample(cls.SOURCE, number))


    #生成驗證碼
    @classmethod
    def gene_graph_captcha(cls):
        # 驗證碼圖檔的寬和高
        width,height = cls.size
        # 建立圖檔
        # RGB為顔色, A: 透明度
        image = Image.new('RGBA',(width,height),cls.__gene_random_color(0,100))
        # 驗證碼的字型
        font = ImageFont.truetype(cls.__gene_random_font(),cls.fontsize)
        # 建立畫筆
        draw = ImageDraw.Draw(image)
        # 生成字元串
        text = cls.gene_text(cls.number)
        # 擷取字型的尺寸
        font_width, font_height = font.getsize(text)
        # 填充字元串
        draw.text(((width - font_width) / 2, (height - font_height) / 2),text,font= font,fill=cls.__gene_random_color(150,255))
        # 繪制幹擾線
        for x in range(0, cls.line_number):
            cls.__gene_line(draw, width, height)
        # 繪制噪點
        cls.__gene_points(draw, 10, width, height)
        return (text,image)
           

3. 背景向前台傳送驗證碼

理一下思路:

  1. 接收繪圖子產品傳來的圖形驗證碼
  2. 用 二進制流操作圖檔驗證碼進行傳輸
  3. 将尋求設定在開始, 這樣才能擷取圖檔驗證碼
  4. 使用

    make_response

    傳輸二進制流, 并設定文本格式

    content_type="image/png"

    ,在前端顯示
from io import BytesIO

@bp.route('/captcha/')
def graph_captcha():
    # 擷取圖形驗證碼的 驗證數字和圖檔
    text, image = Captcha.gene_graph_captcha()
    # BytesIo: 用于操作二進制資料流
    out = BytesIO()
    # 儲存圖檔 fp:out, format: png
    image.save(out, "png") 
    # 将尋求設定從頭(0)開始, (1)從目前位置開始, (2)從尾部開始尋求
    out.seek(0) 
    resp = make_response(out.read())
    # 設定響應的檔案類型
    resp.content_type = "image/png"
    return resp
           
繪制圖檔驗證碼, 并在前端使用

4. 前端設定驗證碼

5. jQuery實作點選圖檔更換驗證碼

$(function () {
    $("#img-captcha").click(function (event) {
       var self = $(this);
       var src = self.attr('src');
       var newsrc = xtparam.setParam(src, "xx", Math.random());
       self.attr('src', newsrc)
    });
});
           

xtparam.js

// xtparam.js
// 粘貼就可以

var xtparam = {
    setParam: function (href,key,value) {
        // 重新加載整個頁面
        var isReplaced = false;
        var urlArray = href.split('?');
        if(urlArray.length > 1){
            var queryArray = urlArray[1].split('&');
            for(var i=0; i < queryArray.length; i++){
                var paramsArray = queryArray[i].split('=');
                if(paramsArray[0] == key){
                    paramsArray[1] = value;
                    queryArray[i] = paramsArray.join('=');
                    isReplaced = true;
                    break;
                }
            }

            if(!isReplaced){
                var params = {};
                params[key] = value;
                if(urlArray.length > 1){
                    href = href + '&' + $.param(params);
                }else{
                    href = href + '?' + $.param(params);
                }
            }else{
                var params = queryArray.join('&');
                urlArray[1] = params;
                href = urlArray.join('?');
            }
        }else{
            var param = {};
            param[key] = value;
            if(urlArray.length > 1){
                href = href + '&' + $.param(param);
            }else{
                href = href + '?' + $.param(param);
            }
        }
        return href;
    }
};