關(guān)于在Django中用Pillow生成圖形驗證碼的記錄

最近因為業(yè)務(wù)需求丧靡,需要重寫圖形驗證碼部分。
使用的是Python3.6歉秫,代碼很簡單蛾洛,看一眼基本就知道其中原理,這里僅作記錄雁芙。

from PIL import (
    Image, ImageDraw, ImageFont, ImageFilter
)
from django.core.cache import cache
from django.conf import settings
from io import BytesIO
import os, random, string, time


class Captcha:
    """
        TODO: 自定義生成圖形驗證碼
        using:  captcha 獲取圖形驗證碼
        using: verify_captcha 驗證圖形驗證碼
    """

    def __init__(self):
        self._code = string.ascii_uppercase + string.digits
        self._width = 100  # 圖片寬
        self._height = 40  # 圖片高
        self._bits = 4
        self._draw_line = True  # 干擾線
        self._line_num = (1, 5)  # 干擾線數(shù)量
        self._bgcolor = random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)  # 背景顏色
        self._font_path = os.path.join(settings.BASE_DIR, 'captcha/fonts/Vera.ttf')
        self.captcha_code = self._generate_shuffle_str()

    # 生成隨機字符串
    def _generate_shuffle_str(self):
        shuffle_list = ','.join(self._code).split(',')
        random.shuffle(shuffle_list)
        return ''.join(shuffle_list[:self._bits])

    # 生成圖像
    def _generate_image(self):
        image = Image.new('RGBA', (self._width, self._height), self._bgcolor)  # 畫布
        font = ImageFont.truetype(self._font_path, 24)  # 用到的字體
        draw = ImageDraw.Draw(image)  # 畫筆
        text = self._generate_shuffle_str()

        # 在畫布上畫字著色
        for i in range(len(text)):
            font_width, font_height = font.getsize(text[i])
            draw.text((self._width / self._bits * (i + 1) - font_width,
                       (self._height - font_height) / random.randint(2, self._bits)),
                      text[i],
                      font=font, fill=(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))

        # 畫上干擾線
        if self._draw_line:
            self._append_line(draw)
        # 畫上躁點
        self._append_points(draw)
        # 應用圖形變換
        image = image.transform((self._width, self._height),
                                Image.AFFINE,
                                (1, 0, 0, 0, 1, 0),
                                Image.BILINEAR)  # 創(chuàng)建扭曲
        image = image.filter(ImageFilter.EDGE_ENHANCE_MORE)  # 漢斯濾鏡轧膘, 邊界加強

        return image

    # 追加躁點
    def _append_points(self, draw):
        chance = min(100, max(0, 5))
        for w in range(self._width):
            for h in range(self._height):
                tmp = random.randint(0, 100)
                if tmp > 100 - chance:
                    draw.point((w, h), fill=(0, 0, 0))

    # 追加干擾線
    def _append_line(self, draw):
        for _ in range(random.randint(*self._line_num)):
            begin = random.randint(0, self._width), random.randint(0, self._height)
            end = random.randint(0, self._width), random.randint(0, self._height)
            draw.line([begin, end], fill=(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))

    def captcha(self):
        buf = BytesIO()
        im = self._generate_image()
        tk = self._cache_captcha()
        im.save(buf, 'JPEG')
        im.close()
        buf.seek(0)
        return tk, buf

    # 臨時記錄圖形驗證碼
    def _cache_captcha(self):
        timestamp_key = int(time.time() * 100000000) + random.randint(10, 99)
        cache.set(timestamp_key, self.captcha_code, 300)
        return timestamp_key

    # 驗證圖形驗證碼
    def verify_captcha(self, timestamp_key=None, captcha=None):
        if timestamp_key and captcha and captcha == cache.get(timestamp_key):
            # del the cache data
            cache.delete(timestamp_key)
            return True
        return False

因為我的設(shè)計驗證是key:value形式,所以要把key也傳給移動端却特,這里我使用了下面的方法:

from django.http import JsonResponse, HttpResponse
from django.views.decorators.csrf import csrf_exempt
from .captcha import Captcha
from base64 import b64encode


@csrf_exempt
def get_captcha(request):
    captcha = Captcha()
    tk, im_buf = captcha.captcha()
    # return HttpResponse(im_buf, content_type='image/jpeg')
    return JsonResponse({'recode': 1,
                         'remsg': '獲取成功扶供!',
                         'data': {'timestamp': tk, 'captcha': b64encode(im_buf.read()).decode('utf-8')}})

注釋的部分用于在瀏覽器里面查看圖片驗證碼。
這里在BytesIO那里踩了點坑裂明,主要還是怪自己學藝不精椿浓。

-- 路漫漫其修遠兮,吾將上下而求索闽晦。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末扳碍,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子仙蛉,更是在濱河造成了極大的恐慌笋敞,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,454評論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件荠瘪,死亡現(xiàn)場離奇詭異夯巷,居然都是意外死亡赛惩,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,553評論 3 385
  • 文/潘曉璐 我一進店門趁餐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來喷兼,“玉大人,你說我怎么就攤上這事后雷〖竟撸” “怎么了?”我有些...
    開封第一講書人閱讀 157,921評論 0 348
  • 文/不壞的土叔 我叫張陵臀突,是天一觀的道長勉抓。 經(jīng)常有香客問我,道長候学,這世上最難降的妖魔是什么藕筋? 我笑而不...
    開封第一講書人閱讀 56,648評論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮盒齿,結(jié)果婚禮上念逞,老公的妹妹穿的比我還像新娘。我一直安慰自己边翁,他們只是感情好翎承,可當我...
    茶點故事閱讀 65,770評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著符匾,像睡著了一般叨咖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上啊胶,一...
    開封第一講書人閱讀 49,950評論 1 291
  • 那天甸各,我揣著相機與錄音,去河邊找鬼焰坪。 笑死趣倾,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的某饰。 我是一名探鬼主播儒恋,決...
    沈念sama閱讀 39,090評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼黔漂!你這毒婦竟也來了诫尽?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,817評論 0 268
  • 序言:老撾萬榮一對情侶失蹤炬守,失蹤者是張志新(化名)和其女友劉穎牧嫉,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,275評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡酣藻,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,592評論 2 327
  • 正文 我和宋清朗相戀三年曹洽,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片臊恋。...
    茶點故事閱讀 38,724評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡衣洁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出抖仅,到底是詐尸還是另有隱情,我是刑警寧澤砖第,帶...
    沈念sama閱讀 34,409評論 4 333
  • 正文 年R本政府宣布撤卢,位于F島的核電站,受9級特大地震影響梧兼,放射性物質(zhì)發(fā)生泄漏放吩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 40,052評論 3 316
  • 文/蒙蒙 一羽杰、第九天 我趴在偏房一處隱蔽的房頂上張望绝编。 院中可真熱鬧奕翔,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,815評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽聂渊。三九已至呆躲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間忍抽,已是汗流浹背八孝。 一陣腳步聲響...
    開封第一講書人閱讀 32,043評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鸠项,地道東北人干跛。 一個月前我還...
    沈念sama閱讀 46,503評論 2 361
  • 正文 我出身青樓,卻偏偏與公主長得像祟绊,于是被迫代替她去往敵國和親楼入。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,627評論 2 350

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理久免,服務(wù)發(fā)現(xiàn)浅辙,斷路器,智...
    卡卡羅2017閱讀 134,637評論 18 139
  • Web 端中阎姥,為了防止惡意的流量攻擊或者為了防止自動化提交记舆,都會在頁面中引入驗證碼。驗證碼一般是一些加入了干擾線...
    Kerwong閱讀 5,759評論 0 7
  • 這本書講一個千年小鎮(zhèn)龍盞的故事呼巴,辛七雜泽腮,辛欣來御蒲,安平,王秀滿诊赊,安雪兒等人厚满,但這個故事很精彩,也很曲折碧磅,我從來沒看過...
    人生何夢閱讀 251評論 0 0
  • 每個人,常常在想:如果有時間我要陪陪家人秆撮,如果有機會我要出去走走四濒,如果有可能我要做件大事!卻總是由于種種原因而未能...
    青莧閱讀 687評論 0 0