python製作驗證碼(可畫干擾線、噪點)

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})

4.效果圖

        
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章