1.寫作由來
最近練習做一個電商項目,在註冊頁面準備加一個驗證碼功能。之前雖然也寫過一個簡單的驗證碼生成函數,但如今來看,真是有些‘勉強’,於是結合網上的一些文章,重新改良了一番。
2.實現思路
2.1製作驗證碼,我們首先得把驗證碼所必須的元素搞清楚。下面是我認爲必需的一些參數。
參數名 | 參數含義 |
---|---|
width | 生成圖片的寬度 |
height | 生成圖片的高度 |
bgColor | 生成圖片的背景色 |
num | 驗證碼字符個數 |
fontPath | 字體路徑 |
fontSize | 字體大小 |
code | 驗證碼內容(作爲返回值,用於驗證) |
img | 生成圖片對象 |
savePath | 生成圖片的保存路徑 |
2.2弄清楚參數,還要考慮下驗證碼的呈現方式。如:字符隨機產生、顏色隨機更換、字符位置隨機改變、干擾線的數量、噪點的數量…考慮清楚這些,便可以着手敲代碼了。
3.代碼實現
# coding:utf-8
import random
import os
import string
import json
from PIL import Image, ImageDraw, ImageFont
# 將隨機函數賦給變量 rdint
rdint = random.randint
class vertifyCode():
def __init__(self, width, height, bgColor, num, fontPath, fontSize, savePath):
self.width = width # 生成圖片寬度
self.height = height # 生成圖片高度
self.bgColor = bgColor # 生成圖片背景顏色
self.num = num # 驗證碼字符個數
self.fontPath = fontPath # 字體路徑
self.fontSzie = fontSize # 字體大小
self.code = '' # 驗證內容
self.img = Image.new('RGB', (self.width, self.height), self.bgColor) # 生成圖片對象
self.savePath = savePath #生成圖片的保存路徑
# 獲取隨機顏色,RGB格式
def get_random_Color(self):
c1 = rdint(50, 150)
c2 = rdint(50, 150)
c3 = rdint(50, 150)
return (c1, c2, c3)
# 隨機生成1位字符,作爲驗證碼內容
def get_random_char(self):
c = ''.join(random.sample(string.ascii_letters + string.digits, 1))
self.code += c
return c
# 生成隨機位置(x,y)
def get_random_xy(self):
x = rdint(0, int(self.width))
y = rdint(0, int(self.height))
return (x, y)
# 根據字體文件生成字體,無字體文件則生成默認字體
def get_font(self):
if self.fontPath:
if os.path.exists(self.fontPath):
if self.fontSzie and self.fontSzie > 0 and self.fontSzie < self.height:
size = self.fontSzie
else:
size = rdint(int(self.height /1.5), int(self.height - 10))
font = ImageFont.truetype(self.fontPath, size)
return font
raise Exception('字體文件不存在或路徑錯誤', self.fontPath)
return ImageFont.load_default().font
# 圖片旋轉
def rotate(self):
deg = int(self.height / 3) # 旋轉角度
self.img = self.img.rotate(rdint(0, deg), expand=0)
# 畫n條幹擾線
def drawLine(self, n):
draw = ImageDraw.Draw(self.img)
for i in range(n):
draw.line([self.get_random_xy(), self.get_random_xy()],
self.get_random_Color())
del draw
# 畫n個干擾點
def drawPoint(self, n):
draw = ImageDraw.Draw(self.img)
for i in range(n):
draw.point([self.get_random_xy()], self.get_random_Color())
del draw
# 寫驗證碼內容
def drawText(self, position, char, fillColor):
draw = ImageDraw.Draw(self.img)
draw.text(position, char, font=self.get_font(), fill=fillColor)
del draw
# 生成驗證碼圖片,並返回圖片對象
def getVertifyImg(self):
x_start = 2
y_start = 0
for i in range(self.num):
x = x_start + i * int(self.width / (self.num))
y = rdint(y_start, int(self.height / 3))
self.drawText((x, y), self.get_random_char(),
self.get_random_Color())
self.drawLine(3)
self.drawPoint(60)
return self.img
# 將圖片保存到內存,便於前臺點擊刷新
# 將驗證碼保存到session中,返回內存中的圖片數據
def saveInMemory(self, request):
img = self.getVertifyImg()
request.session['code'] = self.code.lower()
f = BytesIO() # 開闢內存空間
img.save(f, 'png')
return f.getvalue()
# 將圖片保存在本地,並以json格式返回驗證碼內容
def saveInLocal(self):
img = self.getVertifyImg()
try:
img.save(self.savePath)
except:
raise NotADirectoryError('保存路徑錯誤或不存在:' + self.savePath)
return json.dumps({'code': self.code})