python生成自定义图片验证码(pilow简单版)

本文介绍了如何使用Python和第三方库如PIL和FastAPI创建随机验证码。代码中详细展示了生成验证码图像的过程,包括添加干扰元素、边框模糊以及将结果以BytesIO形式返回,以便于FastAPI应用中的响应输出。
摘要由CSDN通过智能技术生成

from io import BytesIO
from random import randint, sample
from string import ascii_letters, digits
from typing import Tuple

# 第三方包
from PIL.Image import new
from PIL.ImageDraw import Draw
from PIL.ImageFilter import EDGE_ENHANCE_MORE
from PIL.ImageFont import truetype


# 创建随机颜色
async def random_color():
    """
        生成随机颜色
        :return:
        """
    return randint(150, 235), randint(150, 235), randint(150, 235)


# 生成验证吗
class CheckCode(object):

    def __init__(
        self,
        image_width: int = 150,
        image_height: int = 40,
        character_length: int = 5,
        font_size: int = 30,
        mode: str = 'RGB',
        color: Tuple[int] = (255, 255, 255),
        font_file: str = '/usr/share/fonts/truetype/dejavu/DejaVuSansMono-Bold.ttf',
    ) -> None:
        self.image_width = image_width
        self.image_height = image_height
        self.character_length = character_length
        self.image = new(mode=mode, size=(image_width, image_height), color=color)
        self.draw = Draw(im=self.image, mode=mode)
        self.create_font = truetype(font=font_file, size=font_size)
        self.random_characters = sample(ascii_letters + digits, self.character_length)

    # 开始创建
    async def create_check_code(self):
        # 将字符写入图框,并配上随机颜色
        for _index, _character in enumerate(self.random_characters):
            font_start_height = randint(-4, 4)
            self.draw.text(
                xy=[_index * self.image_width / self.character_length, font_start_height],
                text=_character,
                font=self.create_font,
                fill=await random_color())

        for _ in range(150):
            # 写干扰点
            self.draw.point([randint(0, self.image_width),
                             randint(0, self.image_height)],
                            fill=await random_color())

            # 写干扰圆圈
            self.draw.point([randint(0, self.image_width),
                             randint(0, self.image_height)],
                            fill=await random_color())
            x = randint(0, self.image_width)
            y = randint(0, self.image_height)
            radius = randint(2, 4)
            self.draw.arc(xy=(x - radius, y - radius, x + radius, y + radius),
                          start=0,
                          end=90,
                          fill=await random_color())

        # 画干扰线
        for _ in range(10):
            x1 = randint(0, self.image_width)
            y1 = randint(0, self.image_height)
            x2 = randint(0, self.image_width)
            y2 = randint(0, self.image_height)
            self.draw.line((x1, y1, x2, y2), fill=await random_color())
        
        # 给图框修改边模糊
        self.image.filter(EDGE_ENHANCE_MORE)
        # 将image对象转换成bytesIO
        image_io = BytesIO()
        self.image.save(image_io, 'png')
        self.image.close()
        # 这个很重要,将图片文件指针回到0,不然读取不到图片bytes
        image_io.seek(0)
        return image_io, ''.join(self.random_characters).lower()


async def main(int_index):
    # 2. 写入文件
    from app.system_module.method import CheckCode
    init_image = CheckCode()
    image, code = await init_image.create_check_code()
    print(code)
    with open(f'code{int_index}.png', 'wb') as f:
        f.write(image.read())


if __name__ == '__main__':
    from asyncio import run

    # for i in range(5):
    # run(main=main(int_index=0))

转化成 bytesIO是为了通用化返回,如果需要可以自行修改

我的项目是fastapi的转化对象可以直接作为StreamingResponse对象的接受参数

# 第三方包
from fastapi.responses import StreamingResponse

# 项目内包
from .method import CheckCode


# 获取验证码
async def query_check_code():
    _image, _code = await CheckCode().create_check_code()

    return StreamingResponse(content=_image, media_type="image/png")

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值