作者:
12345
管理员
创建日期:2024年12月3日 18:25
浏览量:22
import random
from PIL import Image, ImageDraw, ImageFont
class Captcha():
def __init__(self, width, height, mode=None, color=None):
"""
初始化--> 画文本--> (画干扰效果)--> 显示
:param mode: mode-->默认RGBA
:param width: 验证码的宽
:param height: 验证码的高
:param color: (num, num, num)
"""
self.mode = mode
if mode: # 默认RGBA
self.mode = mode
else:
self.mode = 'RGBA'
self.width = width
self.height = height
self.color = None
if color: # 默认(255, 255, 255)
self._color = color
else:
self._color = (255, 255, 255)
# 定义使用Image类实例化一个图片
self.img = Image.new(mode=self.mode, size=(self.width, self.height), color=self._color)
def draw_out(self,_show=True,path="captcha.png"):
# 把生成的图片保存为"pic.png"格式
with open(path, 'wb') as f:
self.img.save(f, format='png')
if _show:
# 显示图片
self.img.show()
# 画文本
def draw_text(self, font_path, num, number=True, a_font=False, A_font=False):
"""
若要添加字样,则设为true,数字默认开启
:param font_path: 字样文件
:param num: 验证码字符个数
:param number: 是否开启数字
:param a_font: 是否开启小写字母
:param A_font: 是否开启大写字母
:return: None
"""
self.img = Image.new(mode=self.mode, size=(self.width, self.height), color=self._color)
draw = ImageDraw.Draw(self.img, mode=self.mode)
# 定义字体
font1 = font_path
font = ImageFont.truetype(font1, 50) # 字体大小
data = self.get_font(number=number, a_font=a_font, A_font=A_font)
for i in range(num):
# 数字,大写字母,小谢字母
text = random.choice(data)
color = self.get_color()
draw.text([i * 50 + 12, -10], text, color, font=font)
def draw_text_rotate(self, font_path, num, number=True, a_font=False, A_font=False):
"""
若要添加字样,则设为true,数字默认开启
:param font_path: 字样文件
:param num: 验证码字符个数
:param number: 是否开启数字
:param a_font: 是否开启小写字母
:param A_font: 是否开启大写字母
:return: None
"""
self.img = Image.new(mode=self.mode, size=(self.width, self.height), color=self._color)
font1 = font_path
font = ImageFont.truetype(font1, 60)
data = self.get_font(number=number, a_font=a_font, A_font=A_font)
text = ""
for i in range(num):
# 数字,大写字母,小谢字母
char = random.choice(data)
text += char
color = self.get_color()
global IMG
img0 = Image.new(mode=self.mode, size=(self.width, self.height),
color=(255, 255, 255))
draw0 = ImageDraw.Draw(img0, mode='RGBA')
draw0.text((0, 0), char, color, font=font)
# 获得一个旋转字
img1 = img0.rotate(random.uniform(-35, 35), Image.BILINEAR,
translate=((i * 65) + 25, 0), center=(0, 0),
expand=0)
if i == 0: # 当前旋转字与上一个叠加
IMG = img1
else:
IMG = Image.composite(img1, IMG, img1)
blank = Image.new(mode='RGBA', size=IMG.size, color=(255,) * 3) # 白背景
self.img = Image.composite(IMG, blank, IMG) # 补全旋转字的空缺
return text
# 画干扰点
def draw_point(self, num):
# 生成img该对象上的画笔
draw = ImageDraw.Draw(self.img, mode=self.mode)
for i in range(num):
x = random.randint(0, self.width)
y = random.randint(0, self.height)
color = self.get_color()
draw.point([x, y], fill=color)
# self.draw_out()
# 画干扰园
def draw_arc(self, num):
# 生成img该对象上的画笔
draw = ImageDraw.Draw(self.img, mode=self.mode)
for i in range(num):
x = random.randint(0, self.width)
y = random.randint(0, self.height)
color = self.get_color()
draw.arc([x, y, x + 15, y + 15], 0, 360, fill=color)
# self.draw_out()
# 画干扰线
def draw_line(self, num):
# 生成img该对象上的画笔
draw = ImageDraw.Draw(self.img, mode=self.mode)
for i in range(num):
x1 = random.randint(0, self.width)
y1 = random.randint(0, self.height)
x2 = random.randint(0, self.width)
y2 = random.randint(0, self.height)
color = self.get_color()
draw.line([x1, y1, x2, y2], fill=color)
# self.draw_out()
def get_font(self, number=False, a_font=False, A_font=False):
data = []
if number:
for i in range(0, 10):
data.append(str(i))
if A_font:
for i in range(65, 91):
data.append(chr(i))
if a_font:
for i in range(97, 123):
data.append(chr(i))
return data
def get_color(self):
self.color = (random.randint(0, self._color[0]),
random.randint(0, self._color[1]), random.randint(0, self._color[2]))
return self.color
def make_captcha(self, _show=False, path="captcha.png"):
text = self.draw_text_rotate(font_path='simkai.ttf', num=4, a_font=True, A_font=True)
# pil.draw_text(font_path='UbuntuMono-B.ttf', num=4, a_font=True, A_font=True)
self.draw_point(500)
self.draw_arc(15)
self.draw_line(10)
self.draw_out(_show, path)
return text
captcha = Captcha(width=280, height=70)
for i in range(10):
print(captcha.make_captcha(path=f"captcha{i}.png"))
import string
import random
from PIL import Image, ImageFont, ImageDraw
class Captcha():
'''
captcha_size: 验证码图片尺寸
font_size: 字体大小
text_number: 验证码中字符个数
line_number: 线条个数
background_color: 验证码的背景颜色
sources: 取样字符集。验证码中的字符就是随机从这个里面选取的
save_format: 验证码保存格式
'''
def __init__(self, captcha_size=(150,100), font_size=30,text_number=4, line_number=10, background_color=(255, 255, 255), sources=None, save_format='png'):
self.text_number = text_number
self.line_number = line_number
self.captcha_size = captcha_size
self.background_color = background_color
self.font_size = font_size
self.format = save_format
if sources:
self.sources = sources
else:
self.sources = string.ascii_letters + string.digits
def get_text(self):
text = random.sample(self.sources,k=self.text_number)
return ''.join(text)
def get_font_color(self):
font_color = (random.randint(0, 150), random.randint(0, 150), random.randint(0, 150))
return font_color
def get_line_color(self):
line_color = (random.randint(0, 250), random.randint(0, 255), random.randint(0, 250))
return line_color
def draw_text(self,draw, text, font, captcha_width, captcha_height, spacing=20):
'''
在图片上绘制传入的字符
:param draw: 画笔对象
:param text: 绘制的所有字符
:param font: 字体对象
:param captcha_width: 验证码的宽度
:param captcha_height: 验证码的高度
:param spacing: 每个字符的间隙
:return:
'''
# 得到这一窜字符的高度和宽度
text_width, text_height = font.getsize(text)
# 得到每个字体的大概宽度
every_value_width = int(text_width / 4)
# 这一窜字符的总长度
text_length = len(text)
# 每两个字符之间拥有间隙,获取总的间隙
total_spacing = (text_length-1) * spacing
if total_spacing + text_width >= captcha_width:
raise ValueError("字体加中间空隙超过图片宽度!")
# 获取第一个字符绘制位置
start_width = int( (captcha_width - text_width - total_spacing) / 2 )
start_height = int( (captcha_height - text_height) / 2 )
# 依次绘制每个字符
for value in text:
position = start_width, start_height
# print(position)
# 绘制text
draw.text(position, value, font=font, fill=self.get_font_color())
# 改变下一个字符的开始绘制位置
start_width = start_width + every_value_width + spacing
def draw_line(self, draw, captcha_width, captcha_height):
'''
绘制线条
:param draw: 画笔对象
:param captcha_width: 验证码的宽度
:param captcha_height: 验证码的高度
:return:
'''
# 随机获取开始位置的坐标
begin = (random.randint(0,captcha_width/2), random.randint(0, captcha_height))
# 随机获取结束位置的坐标
end = (random.randint(captcha_width/2,captcha_width), random.randint(0, captcha_height))
draw.line([begin, end], fill=self.get_line_color())
def draw_point(self, draw, point_chance, width, height):
'''
绘制小圆点
:param draw: 画笔对象
:param point_chance: 绘制小圆点的几率 概率为 point_chance/100
:param width: 验证码宽度
:param height: 验证码高度
:return:
'''
# 按照概率随机绘制小圆点
for w in range(width):
for h in range(height):
tmp = random.randint(0, 100)
if tmp < point_chance:
draw.point((w, h), fill=self.get_line_color())
def make_captcha(self, name = 'captcha.png'):
# 获取验证码的宽度, 高度
width, height = self.captcha_size
# 生成一张图片
captcha = Image.new('RGB',self.captcha_size,self.background_color)
# 获取字体对象
font = ImageFont.truetype('simkai.ttf',self.font_size)
# 获取画笔对象
draw = ImageDraw.Draw(captcha)
# 得到绘制的字符
text = self.get_text()
# 绘制字符
self.draw_text(draw, text, font, width, height)
# 绘制线条
for i in range(self.line_number):
self.draw_line(draw, width, height)
# 绘制小圆点 10是概率 10/100, 10%的概率
self.draw_point(draw,10,width,height)
# 保存图片
captcha.save(name, format=self.format)
# 显示图片
# captcha.show()
return text
if __name__ == "__main__":
captcha = Captcha()
for i in range(10):
text = captcha.make_captcha(f"captcha{i}.png")
print("验证码文本:", text)