制作网站登录时的图片验证码
#直接上图
1.使用的库:PLI(pillow)
2.生成一张指定大小随机颜色的图片
2.1 颜色的处理使用(r,g,b)格式,r, g, b 的范围是[0, 255], 使用random模块的randint方法生成3
个随机数
def random_color():
c1 = random.randint(0, 255)
c2 = random.randint(0, 255)
c3 = random.randint(0, 255)
return c1, c2, c3
2.2 生成一张指定大小的图片
def random_color():
c1 = random.randint(0, 255)
c2 = random.randint(0, 255)
c3 = random.randint(0, 255)
return c1, c2, c3
def generate_picture(width=120, height=35):
image = Image.new('RGB', (width, height), random_color())
return image
if __name__ == '__main__':
image = generate_picture()
image.save('test.png')
3.在图片上写上随机数字和字母
3.1 生成随机数字和字母
def get_random_str():
'''
获取一个随机字符, 数字或小写字母
:return:
'''
random_num = str(random.randint(0, 9))
random_low_alpha = chr(random.randint(97, 122))
random_char = random.choice([random_num, random_low_alpha])
return random_char
使用random模块提供的随机函数生成指定长度的字符串
3.2 在image对象上画数字和字母
def draw_str(count, image, font_size):
"""
在图片上写随机字符
:param count: 字符数量
:param image: 图片对象
:param font_size: 字体大小
:return:
"""
draw = ImageDraw.Draw(image)
# 获取一个font字体对象参数是ttf的字体文件的目录,以及字体的大小
font_file = os.path.join('Andale Mono.ttf')
font = ImageFont.truetype(font_file, size=font_size)
temp = []
for i in range(count):
random_char = random_str()
draw.text((10+i*30, -2), random_char, random_color(), font=font)
temp.append(random_char)
valid_str = "".join(temp) # 验证码
return valid_str, image
if __name__ == '__main__':
image = generate_picture()
valid_str, image = draw_str(4, image, 35)
image.save('test.png')
4.制造噪点
为了防止验证码被轻易的破解,还应该在图片上制造一些噪点,随机画几条线,随机画几个点
def noise(image, width=120, height=35, line_count=3, point_count=20):
'''
:param image: 图片对象
:param width: 图片宽度
:param height: 图片高度
:param line_count: 线条数量
:param point_count: 点的数量
:return:
'''
draw = ImageDraw.Draw(image)
for i in range(line_count):
x1 = random.randint(0, width)
x2 = random.randint(0, width)
y1 = random.randint(0, height)
y2 = random.randint(0, height)
draw.line((x1, y1, x2, y2), fill=random_color())
# 画点
for i in range(point_count):
draw.point([random.randint(0, width), random.randint(0, height)], fill=random_color())
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y + 4), 0, 90, fill=random_color())
return image
if __name__ == '__main__':
image = generate_picture()
valid_str, image = draw_str(4, image, 35)
image = noise(image)
image.save('test.png')
5.生成base64编码的图片
实践中,如果是生成网站注册使用的验证码图片,一般来说不会将其保存到图片文件中,因为这会生成大量的小图片,完全没必要。我们可以将图片的内容保存到BytesIO对象中,最终生成base64编码的图片,这样,向前端传回去的就是字符串,格式为
data:image/jpeg;base64,iVBORw0KGgoAAAANSUhEUgAAAH…
data:image/jpeg;base64 这一段是固定写法,逗号剩余的部分是图片经过base64编码后的字符串
def valid_code():
"""
生成图片验证码,并对图片进行base64编码
:return:
"""
image = generate_picture()
valid_str, image = draw_str(4, image, 35)
image = noise(image)
f = BytesIO()
image.save(f, 'png') # 保存到BytesIO对象中, 格式为png
data = f.getvalue()
f.close()
encode_data = base64.b64encode(data)
data = str(encode_data, encoding='utf-8')
img_data = "data:image/jpeg;base64,{data}".format(data=data)
return valid_str, img_data
if __name__ == '__main__':
print(valid_code())
6.全部代码
为了向你阐述生成验证码图片的过程,我将整个过程进行拆解,因此代码也被拆解的凌乱,你可以将这些代码整合,以便在实际应用中使用
import os
import random
import base64
from io import BytesIO
from PIL import Image
from PIL import ImageDraw
from PIL import ImageFont
def random_color():
# 随机产生一种颜色
c1 = random.randint(0, 255)
c2 = random.randint(0, 255)
c3 = random.randint(0, 255)
return c1, c2, c3
def generate_picture(width=240, height=70):
# 制作一个宽为240,高为70的白色底板
image = Image.new('RGB', (width, height), "white")
return image
def random_str():
'''
获取一个随机字符, 数字或小写字母
:return:
'''
random_num = str(random.randint(0, 9))
random_low_alpha = chr(random.randint(97, 122))
random_char = random.choice([random_num, random_low_alpha])
return random_char
def draw_str(count, image, font_size):
"""
在图片上写随机字符
:param count: 字符数量
:param image: 图片对象
:param font_size: 字体大小
:return:
"""
draw = ImageDraw.Draw(image) #在image上面绘图
# 获取一个font字体对象参数是ttf的字体文件的目录,以及字体的大小
font_file = os.path.join('NotoSansCJK-Bold.ttc')
font = ImageFont.truetype(font_file, size=font_size)
temp = []
for i in range(count):
random_char = random_str()
draw.text((10+i*60, -20), random_char, random_color(), font=font)
temp.append(random_char)
valid_str = "".join(temp) # 验证码
return valid_str, image
def noise(image, width=240, height=70, line_count=10, point_count=500):
'''
:param image: 图片对象
:param width: 图片宽度
:param height: 图片高度
:param line_count: 线条数量
:param point_count: 点的数量
:return:
'''
draw = ImageDraw.Draw(image) # 在image上面进行操作
for i in range(line_count):
x1 = random.randint(0, width)
x2 = random.randint(0, width)
y1 = random.randint(0, height)
y2 = random.randint(0, height)
draw.line((x1, y1, x2, y2), fill=random_color(),width=3)
# 画点
for i in range(point_count):
draw.point([random.randint(0, width), random.randint(0, height)], fill=random_color())
x = random.randint(0, width)
y = random.randint(0, height)
draw.arc((x, y, x + 4, y + 4), 0, 120, fill=random_color())
return image
def valid_code():
"""
生成图片验证码,并对图片进行base64编码
count: 字符数量
:image: 图片对象
font_size: 字体大小
"""
image = generate_picture() #制作一个白色底片
count = 4
font_size = 70
valid_str, image = draw_str(count, image, font_size)
image = noise(image) # 对图片加干扰素,加干扰线和干扰点
f = BytesIO()
image.save(f, 'png') # 保存到BytesIO对象中, 格式为png
image.save('code.png') # 保存验证码
data = f.getvalue() # 转化为二进制数进行解析
f.close()
encode_data = base64.b64encode(data) #使用bs64进行加密
data = str(encode_data, encoding='utf-8')
img_data = "data:image/jpeg;base64,{data}".format(data=data)
return valid_str, img_data
if __name__ == '__main__':
print(valid_code())