Flask實戰第40天:圖片驗證碼生成技術


圖片驗證碼生成

安裝pillow

pip install pillow

在utils下新建python package命名為captcha

把需要需要用到的字體放在captcha下

編輯captcha.__init__.py, 生成驗證碼

import random
import string
# Image:一個畫布
# ImageDraw:一個畫筆
# ImageFont:畫筆的字體

# pip install pillow
from PIL import Image, ImageDraw, ImageFont


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 = [
            'Courgette-Regular.ttf',
            'LHANDW.TTF',
            'Lobster-Regular.ttf',
            'verdana.ttf'
        ]
        font = random.choice(fonts)
        return 'utils/captcha/' + font

    # 用來隨機生成一個字符串
    @classmethod
    def gene_text(cls, number):
        #num是生成驗證碼的位數
        return ''.join(random.sample(cls.SOURCE, number))

    # 生成驗證碼
    @classmethod
    def gene_graph_captcha(cls):
        #驗證碼圖片的高和寬
        width, height = cls.size
        #創建圖片
        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)
captcha.__init__.py

測試的時候我發現有些字體會導致程序崩潰,所以,我只設置了一個字體  fonts = ['verdana.ttf']

編輯視圖。我們把它放到 公共的common里面去,編輯common.views.py

from flask import Blueprint, make_response
from utils.captcha import Captcha
from io import BytesIO

bp = Blueprint('common', __name__, url_prefix='/c')  #common太長,改為c

@bp.route('/')
def index():
    return 'common index'


@bp.route('/graph_captcha/')
def graph_captcha():
    text, image = Captcha.gene_graph_captcha()
    out = BytesIO()
    image.save(out, 'png')
    out.seek(0)
    resp = make_response(out.read())
    resp.content_type = 'image/png'
    return resp

訪問http://127.0.0.1:5000/c/graph_captcha/

圖片驗證放到注冊頁面。點擊一次更換一張

圖片驗證碼放在注冊頁面比較簡單,只需要把編輯front_signup.html,把里面的“圖片驗證碼”字換成img標簽,src設置成圖片驗證碼的url

<div class="input-group">
    <input type="text" class="form-control" name="graph_captcha" placeholder="圖形驗證碼">
    <span class="input-group-addon captcha-addon"> <!--加了一個類captcha-addon-->
         <img  id="captcha-img" src="{{ url_for('common.graph_captcha') }}"><!--加了id aptcha-img-->
    </span>
</div>


<!--樣式-->
.captcha-addon{
     padding: 0;  //這是內邊距為0,因為input-group-addon有設置內邊距
     overflow: hidden;   //當里面的元素超出則隱藏
}

#captcha-img{
      height: 32px;   //設置圖片的高度為32px
      cursor: pointer;   //當鼠標移到圖片上變成手的圖標
}

還有個需求就是,我們點擊一個圖片驗證碼,則需要更換成另外一個。

圖片驗證碼更換,只需要替換它的url就可以,但是它的url就是一個http://127.0.0.1:5000/common/captcha/

所以只需要請求的時候加個參數http://127.0.0.1:5000/front/captcha/?xxx=<隨機數>即可

我還需要對?xxx=<隨機數>做處理,不然當用戶點擊多次,?xxx=<隨機數>&xxx=<隨機數>...變得很長,而我們只需要一個就可以了,這里封裝了一個js, 存放在static/common/js/bbsparams.js中

/**
 * Created by Administrator on 2017/3/24.
 */

var bbsparam = {
    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;
    }
};
bbsparams

然后在static/front/js/下新建front_signup.js,當點擊圖片時更換src

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

在signup.html中引入上面兩個js

<script src="{{ url_for('static', filename='common/js/bbsparam.js') }}"></script>
<script src="{{ url_for('static', filename='front/js/front_signup.js') }}"></script>

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM