【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
:是為了在點選時切換圖片,當每一次點選時,向後端傳送一次請求