110 lines
3.6 KiB
Python
110 lines
3.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""
|
|
@Author: 孟颖
|
|
@email: 652044581@qq.com
|
|
@date: 2023/4/13 13:36
|
|
@desc: 生成验证码
|
|
"""
|
|
import pathlib
|
|
import random
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
from io import BytesIO
|
|
import base64
|
|
from pathlib import Path
|
|
|
|
|
|
class CaptchaImage:
|
|
|
|
def __init__(self, width=130, height=35, string_count=4, font_size=30, noise_line=3, noise_point=30):
|
|
"""
|
|
:param width: 图片宽度
|
|
:param height: 图片高度
|
|
:param string_count: 验证码的数量
|
|
:param font_size: 字体的大小
|
|
:param noise_line: 噪声线的数量
|
|
:param noise_point: 噪声点的数量
|
|
"""
|
|
self.width = width
|
|
self.height = height
|
|
self.string_count = string_count
|
|
self.font_size = font_size
|
|
self.noise_line = noise_line
|
|
self.noise_point = noise_point
|
|
|
|
# 生成验证码
|
|
def generate(self, width=120, height=35):
|
|
image = self.background()
|
|
captcha_string, image = self.draw_string(image)
|
|
image: Image = self.noise(image)
|
|
image = image.resize((width, height), resample=Image.BICUBIC)
|
|
output_buffer = BytesIO()
|
|
image.save(output_buffer, format='png')
|
|
binary_data = output_buffer.getvalue()
|
|
image_base64 = self.io2base64(binary_data)
|
|
return captcha_string, image_base64
|
|
|
|
# io转base64
|
|
def io2base64(self, content: bytes):
|
|
encode_data = base64.b64encode(content)
|
|
return str(encode_data, encoding='utf-8')
|
|
|
|
# 生成背景
|
|
def background(self):
|
|
background_color = (255, 255, 255)
|
|
image = Image.new('RGB', (self.width, self.height), background_color)
|
|
return image
|
|
|
|
# 随机颜色
|
|
def random_color(self):
|
|
c1 = random.randint(0, 200)
|
|
c2 = random.randint(0, 200)
|
|
c3 = random.randint(0, 200)
|
|
return c1, c2, c3
|
|
|
|
# 生成随机字符串
|
|
def random_string(self):
|
|
random_num = str(random.randint(0, 9))
|
|
random_low_alpha = chr(random.randint(97, 122))
|
|
return random.choice([random_num, random_low_alpha])
|
|
|
|
# 合成文字
|
|
def draw_string(self, image: Image):
|
|
draw = ImageDraw.Draw(image)
|
|
font_file = pathlib.Path.joinpath(Path(__file__).parent, "static/fontBold.ttf").as_posix()
|
|
font = ImageFont.truetype(font=font_file, size=self.font_size)
|
|
string_container = []
|
|
for i in range(self.string_count):
|
|
random_char = self.random_string()
|
|
draw.text((10 + i * 30, -2), random_char, self.random_color(), font=font)
|
|
string_container.append(random_char)
|
|
captcha_string = "".join(string_container)
|
|
return captcha_string, image
|
|
|
|
# 生成噪声
|
|
def noise(self, image: Image):
|
|
|
|
draw = ImageDraw.Draw(image)
|
|
# 噪声线
|
|
for i in range(self.noise_line):
|
|
x1 = random.randint(0, self.width)
|
|
x2 = random.randint(0, self.width)
|
|
y1 = random.randint(0, self.height)
|
|
y2 = random.randint(0, self.height)
|
|
draw.line((x1, y1, x2, y2), fill=self.random_color())
|
|
|
|
# 噪声点
|
|
for i in range(self.noise_point):
|
|
draw.point([random.randint(0, self.width), random.randint(0, self.height)], fill=self.random_color())
|
|
x = random.randint(0, self.width)
|
|
y = random.randint(0, self.height)
|
|
draw.arc((x, y, x + 4, y + 4), 0, 90, fill=self.random_color())
|
|
|
|
return image
|
|
|
|
|
|
if __name__ == '__main__':
|
|
captcha = CaptchaImage()
|
|
|
|
# 生成验证码图片和字符串
|
|
captcha_string, image_base64 = captcha.generate(width=108, height=36)
|