python---生成验证码图片

时间:2023-03-08 16:24:28

工具插件verifycode.py中,记得使用时需要在路由根目录中引入文字资源文件

# coding:utf8
# __author: Administrator
# date: //
# /usr/bin/env python
import random,os
from PIL import Image,ImageDraw,ImageFont,ImageFilter class CreateCode:
def __init__(self,size=(,),img_type="GIF",mode="RGB",bg_color=(,,),
fg_color=(,,),font_size=,font_type="Monaco.ttf",length=,
draw_lines=True,n_line = (,),draw_points=True,point_chance=):
'''
@todo: 生成验证码图片
@param size: 图片的大小,格式(宽,高),默认为(, )
@param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG
@param mode: 图片模式,默认为RGB
@param bg_color: 背景颜色,默认为白色
@param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF
@param font_size: 验证码字体大小
@param font_type: 验证码字体,默认为 ae_AlArabiya.ttf
@param length: 验证码字符个数
@param draw_lines: 是否划干扰线
@param n_lines: 干扰线的条数范围,格式元组,默认为(, ),只有draw_lines为True时有效
@param draw_points: 是否画干扰点
@param point_chance: 干扰点出现的概率,大小范围[, ]
@return: []: PIL Image实例
@return: []: 验证码图片中的字符串
'''
self.size=size
self.img_type=img_type
self.mode=mode
self.bg_color=bg_color
self.fg_color=fg_color
self.font_size = font_size
self.font_type =font_type
self.length = length
self.draw_lines =draw_lines
self.point_chance = point_chance
self.n_line=n_line
self.draw_points=draw_points
#执行初始化函数
self.getAllChar()
self.initPaint()
self.get_chars() def initPaint(self):
'''
初始画布
:return:
'''
self.width,self.height=self.size
self.img = Image.new(self.mode,self.size,self.bg_color)
self.draw = ImageDraw.Draw(self.img)#创建画笔 def getAllChar(self):
'''
获取所有字符串
:return:
'''
_letter_cases = "zxcvbnmasdfghjklqwertyuiop"
_upper_cases = _letter_cases.upper()
_numbers = ''.join(map(str, range(, )))
# 获取所有的字符
self.init_chars = ''.join((_letter_cases, _upper_cases, _numbers)) def get_chars(self):
'''生成给定长度的字符串,返回裂变格式'''
return random.sample(self.init_chars,self.length)#从给定字符串中获取出随机字符 def create_lines(self):
'''绘制干扰线'''
line_num = random.randint(*self.n_line)#从元组中获取线条数目
for i in range(line_num):
#起始点
begin = (random.randint(,self.size[]),random.randint(,self.size[]))#在图片中随机位置
end = (random.randint(,self.size[]),random.randint(,self.size[]))#在图片中随机位置
self.draw.line([begin,end],fill=(,,)) def create_point(self):
'''绘制干扰点'''
chance = min(,max(,int(self.point_chance)))#大小限制在point_chance到100
for w in range(self.width):
for h in range(self.height):
tmp = random.randint(,)
if tmp > -chance:
self.draw.point((w,h),fill=(,,)) def create_strs(self):
'''绘制验证码'''
c_chars = self.get_chars()
strs = ' %s '%' '.join(c_chars) font = ImageFont.truetype(self.font_type,self.font_size)
font_width,font_height = font.getsize(strs) self.draw.text(((self.width-font_width)/,(self.height-font_height)/),strs,font=font,fill=self.fg_color) return ''.join(c_chars) def get_img(self):
if self.draw_lines:
self.create_lines()
if self.draw_points:
self.create_point()
strs = self.create_strs()
# 图形扭曲参数
params = [ - float(random.randint(, )) / ,
,
,
,
- float(random.randint(, )) / ,
float(random.randint(, )) / ,
0.001,
float(random.randint(, )) /
]
img = self.img.transform(self.size, Image.PERSPECTIVE, params) # 创建扭曲 img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大) return img,strs if __name__=="__main__":
img= CreateCode()
image,code=img.get_img()
print(code)

在控制器中调用,并生成路由,在前端调用


from backend.utils.verifycode import CreateCode
class VerifyImgHandler(BaseRequestHandler):
def get(self):
Img = CreateCode(img_type="PNG")
img,code = Img.get_img()
self.session['code']=code
#StringIO操作的只能是str,如果要操作二进制数据,就需要使用BytesIO。
#BytesIO实现了在内存中读写bytes,我们创建一个BytesIO,然后写入一些bytes
mstream = io.BytesIO() # 创建一个BytesIO临时保存生成图片数据
img.save(mstream,"PNG")#将返回的验证码图片数据,添加到BytesIO临时保存 self.write(mstream.getvalue())#从BytesIO临时保存,获取图片返回给img的 src= 进行显示

路由添加:

(r"/getcode",AccountController.VerifyImgHandler)

前端代码:

    <div class="col-sm-4">
<img style="width: 100%;height: 100%" id="code" onclick="changeCode(this);" src="/getcode"/>
</div>
    function changeCode(ths){
var src =$(ths).attr("src")
arr = src.split("?")
src =arr[]+'?'+Math.random()
$(ths).attr("src",src)
}

函数模板使用:

#!/usr/bin/env python
# -*- coding:utf- -*- import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter _letter_cases = "abcdefghjkmnpqrstuvwxy" # 小写字母,去除可能干扰的i,l,o,z
_upper_cases = _letter_cases.upper() # 大写字母
_numbers = ''.join(map(str, range(, ))) # 数字
init_chars = ''.join((_letter_cases, _upper_cases, _numbers)) def create_validate_code(size=(, ),
chars=init_chars,
img_type="GIF",
mode="RGB",
bg_color=(, , ),
fg_color=(, , ),
font_size=,
font_type="Monaco.ttf",
length=,
draw_lines=True,
n_line=(, ),
draw_points=True,
point_chance=):
"""
@todo: 生成验证码图片
@param size: 图片的大小,格式(宽,高),默认为(, )
@param chars: 允许的字符集合,格式字符串
@param img_type: 图片保存的格式,默认为GIF,可选的为GIF,JPEG,TIFF,PNG
@param mode: 图片模式,默认为RGB
@param bg_color: 背景颜色,默认为白色
@param fg_color: 前景色,验证码字符颜色,默认为蓝色#0000FF
@param font_size: 验证码字体大小
@param font_type: 验证码字体,默认为 ae_AlArabiya.ttf
@param length: 验证码字符个数
@param draw_lines: 是否划干扰线
@param n_lines: 干扰线的条数范围,格式元组,默认为(, ),只有draw_lines为True时有效
@param draw_points: 是否画干扰点
@param point_chance: 干扰点出现的概率,大小范围[, ]
@return: []: PIL Image实例
@return: []: 验证码图片中的字符串
""" width, height = size # 宽高
# 创建图形
img = Image.new(mode, size, bg_color)
draw = ImageDraw.Draw(img) # 创建画笔 def get_chars():
"""生成给定长度的字符串,返回列表格式"""
return random.sample(chars, length) def create_lines():
"""绘制干扰线"""
line_num = random.randint(*n_line) # 干扰线条数 for i in range(line_num):
# 起始点
begin = (random.randint(, size[]), random.randint(, size[]))
# 结束点
end = (random.randint(, size[]), random.randint(, size[]))
draw.line([begin, end], fill=(, , )) def create_points():
"""绘制干扰点"""
chance = min(, max(, int(point_chance))) # 大小限制在[, ] for w in range(width):
for h in range(height):
tmp = random.randint(, )
if tmp > - chance:
draw.point((w, h), fill=(, , )) def create_strs():
"""绘制验证码字符"""
c_chars = get_chars()
strs = ' %s ' % ' '.join(c_chars) # 每个字符前后以空格隔开 font = ImageFont.truetype(font_type, font_size)
font_width, font_height = font.getsize(strs) draw.text(((width - font_width) / , (height - font_height) / ),
strs, font=font, fill=fg_color) return ''.join(c_chars) if draw_lines:
create_lines()
if draw_points:
create_points()
strs = create_strs() # 图形扭曲参数
params = [ - float(random.randint(, )) / ,
,
,
,
- float(random.randint(, )) / ,
float(random.randint(, )) / ,
0.001,
float(random.randint(, )) /
]
img = img.transform(size, Image.PERSPECTIVE, params) # 创建扭曲 img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 滤镜,边界加强(阈值更大) return img, strs

验证码纯函数

调用:

def check_code(req):
stream = BytesIO()  #获取内存块句柄,将数据保存在内存中
img,code = create_validate_code()
img.save(stream,'PNG')
req.session['check_code']=code.lower() return HttpResponse(stream.getvalue())  #获取内存中的数据,返回给页面

或者:

    f = open('1.png','wb')  #获取文件句柄,将数据保存在文件中
img,code = create_validate_code()
img.save(f,"PNG") #将图片二进制数据写入文件中