Django之圖形驗證碼

Lea4ning發表於2024-03-28

【1】生成圖片驗證碼

  • 依賴於pillow模組
  • pip install pillow
  • 使用pillow模組在匯入時使用import PIL,而不是pillow

【1.1】Pillow影像生成模組

from PIL import Image, ImageDraw, ImageFont
# Image : 生成圖片物件
# ImageDraw : 生成畫筆物件
# ImageFont : 控制字型樣式
# 圖片物件
img_obj = Image.new(mode='',size=(width,height),color='顏色')
'''
mode: 影像模式,常見的包括 'L'(灰度影像)、'RGB'(真彩色影像)和 'RGBA'(帶透明通道的影像)等。
size: 影像尺寸,以元組 (width, height) 的形式指定,表示影像的寬度和高度。
color: 影像的顏色,通常使用 RGB 或 RGBA 表示顏色,例如 (255, 0, 0) 表示紅色,(0, 255, 0, 128) 表示半透明的綠色。
'''
# 常用方法
img_obj.open(filename, mode='r')  # 開啟並載入影像檔案。
img_obj.save(fp, format=None, **params)  # 儲存影像到檔案。
img_obj.resize(size, resample=3)  # 調整影像尺寸。
img_obj.rotate(angle, resample=0, expand=0, center=None, translate=None, fillcolor=None)  # 旋轉影像。
img_obj.crop(box=None)  # 裁剪影像。
img_obj.filter(filter)  # 應用濾鏡效果。
# 畫筆物件
draw_obj = ImageDraw.Draw(im='')  # im: The image to draw in.
draw_obj = ImageDraw.Draw(im=img_obj)

# 常用方法
draw_obj.text(xy, text, fill=None, font=None, anchor=None, spacing=0, align="left")  # 在影像上繪製文字。
draw_obj.draw_obj.line(xy, fill=None, width=0, joint=None)  # 在影像上繪製直線。
draw_obj.pieslice(xy, start, end, fill=None, outline=None, width=0)  # 在影像上繪製扇形。
draw_obj.polygon(xy, fill=None, outline=None, width=0)  # 在影像上繪製多邊形。
# 字型樣式
font_obj = ImageFont.truetype(font, size, index=0, encoding='')  # 載入 TrueType 或 OpenType 字型檔案。
font_obj = ImageFont.load_default()  # 載入預設字型。

# 常用方法
getsize(text): 返回給定文字的大小。
getmask(text, mode='', fill=0, direction=None, features=None): 返回給定文字的掩碼。
getmetrics(): 返回字型的度量資訊,如字元寬度、高度等。
getname(): 返回字型的名稱。
get_variation_names(): 返回變體字型的名稱。
get_variation_axes(): 返回變體字型的軸。

【1.2】io記憶體管理器模組

  • 使用io記憶體管理器建立資料流,生成速度快,且不會產生硬碟消耗
from io import BytesIO, StringIO
# BytesIO : 在記憶體中建立二進位制資料流,可以像檔案一樣讀取和寫入位元組資料。
# StringIO :在記憶體中建立字串資料流,可以像檔案一樣讀取和寫入字串資料。
# 生成物件
io_obj = BytesIO()  # 與檔案控制代碼類似
# 常見方法
io_obj.read(size:int)  # 讀取指定位元組數的資料,如果未指定大小,則讀取所有資料
io_obj.readline(size:int)  # 讀取一行資料,如果未指定大小,則讀取整行
io_obj.readlines(hint=-1)  # 讀取所有行並返回列表,如果指定了 hint,則最多讀取 hint 位元組資料
io_obj.write(s)  # 向物件中寫入資料。
io_obj.getvalue()  # 返回物件中的所有資料。
io_obj.seek(offset, whence=0)  # 移動檔案指標到指定位置。
io_obj.tell()  # 返回當前檔案指標的位置。
io_obj.truncate(size=None)  # 截斷檔案到指定大小,如果未指定大小,則截斷到當前位置。
io_obj.flush()  # 將緩衝區的資料寫入到流物件中。

【1.3】依賴Pillow模組和BytesIO物件實現生成圖片驗證碼

from PIL import Image, ImageDraw, ImageFont, ImageFilter
import random
from io import BytesIO


def rgb_number():
    # 生成隨機rgb色值的函式
    return random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)


# 建立圖片驗證碼
def create_verify_code(img_type="RGB", img_size: tuple = (115, 34), img_rgb_number: tuple = None):
    if not img_rgb_number:
        # 如果沒有指定,就生成一個隨機的
        img_rgb_number = rgb_number()
    # 利用 Image 物件定義一個圖片檔案引數
    img_obj = Image.new(mode=img_type, size=img_size, color=img_rgb_number)
    # 圖片的濾鏡效果
    img_obj.filter(ImageFilter.UnsharpMask(radius=2, percent=150, threshold=3))
    # 利用 ImageDraw 物件產生一個畫筆物件
    img_draw = ImageDraw.Draw(img_obj)
    # 利用 ImageFont 物件定義驗證碼字型引數(字型樣式,字型大小)
    img_font = ImageFont.truetype('static/font/漢儀晴空體簡.ttf', 30)

    # 建立隨機驗證碼(數字 + 字母)
    code = ''

    for i in range(4):
        string_list = [
            str(random.randint(0, 9)),
            chr(random.randint(65, 90)),
            chr(random.randint(97, 122))
        ]
        temp = random.choice(string_list)

        # 藉助畫筆物件依次寫入圖片資料((x偏移值,y偏移值),寫入內容,字型顏色,字型樣式)
        img_draw.text((i * 25 + 10, 0), temp, fill=rgb_number(), font=img_font)
        # 拼接隨機字串
        code += temp

    # 隨機驗證碼在登入的檢視函式中需要比對,所以需要找地方存起來,便於其他函式呼叫

    # 生成 IO 物件 操作位元組流資料
    io_obj = BytesIO()
    # 利用 Image 物件儲存圖片資料成指定格式
    img_obj.save(io_obj, "png")
    # 利用 IO 物件讀取儲存的圖片位元組資料
    img_data = io_obj.getvalue()

    # 返回生成的隨機驗證碼和驗證碼的圖片二進位制資料
    return code, img_data
【1.3.1】使用方法
  • 將圖片驗證碼渲染至img標籤的src屬性中
  • img標籤的src屬性,有三種方式可以渲染圖片
    • 透過指定連結渲染圖片http://
    • 透過本地路徑渲染圖片/static/
    • 透過二進位制資料渲染圖片
【1.3.1.1】後端
# 將上述程式碼封裝至檔案中
# views.py

from lib.GenerateVerifyCode import create_verify_code

def verify_code(request):
    captcha, img_data = create_verify_code()
    # 在做校驗時需要使用,所以為其設定一個會話,指定會話的captcha屬性
    request.session['captcha'] = captcha
    # 返回二進位制圖片資料
    return HttpResponse(img_data)

'''設定了session後,其他地方可以透過request.session.get('captcha')獲取到驗證碼資料'''
【1.3.1.2】路由
  • 我們使用透過二進位制資料渲染圖片驗證碼
  • 可以透過反向解析執行檢視函式
path('verify_code/', views.verify_code, name='verify_code')
【1.3.1.3】前端
  • 為圖片驗證碼設定點選切換動作
<img src="{% url 'user:verify_code' %}"
 onclick="this.src='{% url 'verify_code' %}'+'?t='+ new Date().getTime();">
  • onclick:是為了在點選時切換圖片,當每一次點選時,向後端傳送一次請求

相關文章