# -*- coding: utf-8 -*-
# @Time : 19-1-11 上午9:49
# @Author : Felix Wang
import random
from io import BytesIO
# 首先要安装PIL库 pip3 install pillow
from PIL import Image, ImageDraw, ImageFont, ImageFilter
def mkdir(path):
# 引入模块
import os
# 去除首位空格
path = path.strip()
# 去除尾部 \ 符号
path = path.rstrip("\\")
# 判断路径是否存在
# 存在 True
# 不存在 False
isExists = os.path.exists(path)
# 判断结果
if not isExists:
# 如果不存在则创建目录
# 创建目录操作函数
os.makedirs(path)
print(path + ' 创建成功')
return True
else:
# 如果目录存在则不创建,并提示目录已存在
print(path + ' 目录已存在')
return False
class CheckCode:
def __init__(self, font_file, font_size=36, width=240, height=60, char_length=4, start_color_num=0,
end_color_num=255, is_simple=True, is_oncache=False):
"""
初始化
:param font_file: 字体文件
:param font_size: 字体大小,默认36
:param width: 验证码宽度
:param height: 验证码高度
:param char_length: 验证码文字个数
:param start_color_num: 颜色开始的颜色
:param end_color_num: 颜色结束
:param is_simple: 是否是简体中文,默认为True,如果为False则可能包含繁体中文
:param is_oncache: 是否存在缓存中,默认为False,表示以图片方式存储
"""
self.is_oncache = is_oncache
self.is_simple = is_simple
self.font_file = font_file
self.font_size = font_size
self.width = width
self.height = height
self.char_length = char_length
self.start_num = start_color_num
self.end_num = end_color_num
# 定义使用Image类实例化一个长为120px,宽为30px,基于RGB的(255,255,255)颜色的图片
self.image = Image.new('RGB', (self.width, self.height), (255, 255, 255))
# 创建Font对象:
self.font = ImageFont.truetype(self.font_file, self.font_size)
# 创建Draw对象:
self.draw = ImageDraw.Draw(self.image)
# 双下划綫的变量在类中不能直接访问起到保护的作用
self.__code_text = []
def get_random_code(self, time=1):
"""
:param is_simple: 是否包含中文繁体字,默认不包含,True表示不包含
:param time: 返回多少个
:return: 返回一个随机字符列表
"""
is_simple = self.is_simple
codes = []
for i in range(time):
num = chr(random.randint(0x30, 0x39)) # 随机生成数字
lowercase = chr(random.randint(0x61, 0x74)) # 随机生成小写字母
capcase = chr(random.randint(0x41, 0x5a)) # 随机生成大写字母
# Unicode编码的汉字,带繁体字 ,共2万多字
zh = chr(random.randint(0x4e00, 0x9fbf))
# gbk编码的简单汉字,无繁体字
head = random.randint(0xb0, 0xf7)
body = random.randint(0xa1, 0xf9) # 在head区号为55的那一块最后5个汉字是乱码,为了方便缩减下范围
val = f'{head:x}{body:x}'
ch = bytes.fromhex(val).decode('gb2312')
if is_simple:
# code = random.choice([ch, num, lowercase, capcase])
code = random.choice([ch, num, lowercase, capcase])
else:
code = random.choice([zh, num, lowercase, capcase])
codes.append(code)
return codes
# 随机颜色:
def rndColor(self, start, end, randomflag=True):
"""
:param start:
:param end:
:param randomflag: 是否返回随机参数,
:return:
"""
return (random.randint(start, end), random.randint(start, end),
random.randint(start, end))
def rotate(self):
self.image.rotate(random.randint(0, 90), expand=0)
# 随机点
def randPoint(self):
return (random.randint(0, self.width), random.randint(0, self.height))
# 随机线
def randLine(self, num):
draw = ImageDraw.Draw(self.image)
for i in range(0, num):
draw.line([self.randPoint(), self.randPoint()], self.rndColor(0, 255))
del draw
# 获取验证码
def get_codes(self):
return self.__code_text
def draw_pic(self):
# 填充每个像素:
# 单一背景
color = self.rndColor(170, 255) # 可以把背景调浅色
for x in range(self.width):
for y in range(self.height):
self.draw.point((x, y), fill=color)
# 输出文字:
codes = self.get_random_code(time=self.char_length)
self.__code_text = []
for ii in range(self.char_length):
code = self.get_random_code()[0]
self.__code_text.append(code)
self.draw.text([random.randint(int((self.width / 2 - self.font_size / 2) / self.char_length * 2 * ii),
int((self.width / 2 - self.font_size / 2) / self.char_length * 2 * (
ii + 1))), random.randint(0, self.height / 4)],
code, font=self.font, fill=self.rndColor(0, 120)) # 把字体调深色
# self.rotate()
# 画出随机线
self.randLine(10)
# 模糊:
# self.image = self.image.filter(ImageFilter.BLUR)
if self.is_oncache: # 保存在缓存
f = BytesIO()
self.image.save(f, 'jpeg')
return f.getvalue()
else:
# 保存
self.image.save('images/{}.jpg'.format(''.join(self.get_codes())), 'jpeg')
# 创建文件夹,用来存放验证码
mkdir('images')
# 这里的字体采用能识别中文的字体
font_file = '/home/felix/.local/share/fonts/SIMHEI.TTF'
# checkcode = CheckCode(font_file=font_file, is_simple=True, char_length=random.randint(3, 7))
# 生成多张验证码
for i in range(100):
checkcode = CheckCode(font_file=font_file, is_simple=True, char_length=random.randint(3, 7))
checkcode.draw_pic()
# 生成的验证码的内容
codes = checkcode.get_codes()
print(i, codes)