• python生成模拟微信气泡图片


    0. 起因

    众所周知,借刀杀人最为致命,聊天也是如此。

    最近我的群聊画风逐渐变味:

    在这里插入图片描述

    当然,这种图片的生产成本很低,只需在设置页关闭昵称显示,把聊天背景重置为灰色,然后利用截图工具截图,最后保存到手机里,添加到表情包库中即可。

    然而微信头像是会更改的,人的精力也是有限的,经过了两天的狂欢后,我们逐渐意识到这种文化的短期性。

    但是,无所谓,我会出手!我灵光一闪,只要把数据来源从截图变成生成,那么即使微信头像更改,也可以随时替换,如此,便有了此文。

    1. 准备工作

    技术栈:Python内置的 PILPillow)库

    头像文件:可以直接从微信中保存,我们给它命名为 logo.jpg

    主脚本文件:main.py

    (为了方便脚本编写,main.pylogo.jpg 放置在同一目录下)

    提示:下面两张表是写完后折回来后补的

    输入参数含义默认
    text要生成的话“Hello World”
    logo_path要生成的气泡用的头像“logo.jpg”
    save_path图片的保存路径及文件名“save.jpg”
    font_path字体的路径“fonts/msyhl.ttc”
    font_size字体的大小25
    space_lengh间隙的长度20
    bg_height背景的高度64
    输出含义
    savepath一张图片文件

    2. 脚本设计与编写

    我们可以从微信上面随便截一下,看看大概的长度。

    在这里插入图片描述
    通过状态栏的提示可知:370x50 为这张图片的大小。

    我们取一个看起来舒服一点的值,就 64 吧,作为我们绘图的高度,同时我们选择微软雅黑作为。

    至于宽度,我们现在已知左边的头像是一个正方形,正方形和右边的白色背景起泡之间的距离为 20,起泡的长度又视文字的长度而定,所以背景的宽度也是不定的。

    所以我们下一步是,如何估算出 文字生成后的大概大小?

    2.1 估算文字生成后的大概大小

    通过阅读博文:使用Python PIL库获取某个字体渲染后的文本的宽高(应用于检测翻译后的文本是否长度过长)

    我们找到了方案,就是如下的一段函数:

    fontsize=26
    white = (255,255,255)
    def get_font_render_size(text):
        canvas = Image.new('RGB', (2048,2048))
        draw = ImageDraw.Draw(canvas)
        monospace = ImageFont.truetype("msyh.ttc", fontsize)
        draw.text((0, 0), text, font=monospace, fill=white)
        bbox = canvas.getbbox()
        # 宽高
        size = (bbox[2] - bbox[0], bbox[3] - bbox[1])
        return size
    # ————————————————
    # 版权声明:本文为CSDN博主「林新发」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    # 原文链接:https://blog.csdn.net/linxinfa/article/details/116527440
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    具体原理可以去对应博文查看,这里就直接投入使用啦。

    我们进行轻微改动后就可以得到函数,返回值为一个元组(宽, 高)

    def get_font_render_size(text, font_path, font_size):
        """
        :param text: 文字
        :param font_path: 字体路径
        :param font_size: 字体大小
        :return: tuple 宽高
        """
        canvas = Image.new('RGB', (2048, 2048))
        ImageDraw.Draw(canvas).text((0, 0), text, font=ImageFont.truetype(font_path, font_size))
        bbox = canvas.getbbox()
        return bbox[2] - bbox[0], bbox[3] - bbox[1]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    # 计算文字渲染后的长度
    text_width, text_height = get_font_render_size(text, font_path, font_size)
    
    • 1
    • 2

    之后我们用text_width表示文字渲染后的长度

    2.2 绘制背景

    # 定义背景宽度
    bg_width = text_width + space_length
    
    • 1
    • 2

    bg_height作为输入参数出现,无需定义。

    # 生成背景
    bg_img = Image.new(mode='RGB', size=(bg_width + 100, bg_height), color="#F5F5F5")
    
    • 1
    • 2

    2.3 绘制头像

    #读取头像文件,并绘制头像到背景图片
    logo = Image.open(logo_path, mode="r")
    logo = logo.resize((bg_height, bg_height))
    bg_img.paste(logo, (0, 0))
    
    • 1
    • 2
    • 3
    • 4

    2.4 绘制气泡

    2.4.1 绘制圆角矩形
    x, y, w, h, r = bg_height + space_length, 0, text_width + space_length * 1.5, bg_height, space_length
    fill_color = "#FFFFFF"
    draw_object = ImageDraw.Draw(bg_img)
    
    draw_object.ellipse((x, y, x + r, y + r), fill=fill_color)
    draw_object.ellipse((x + w - r, y, x + w, y + r), fill=fill_color)
    draw_object.ellipse((x, y + h - r, x + r, y + h), fill=fill_color)
    draw_object.ellipse((x + w - r, y + h - r, x + w, y + h), fill=fill_color)
    
    draw_object.rectangle((x + r / 2, y, x + w - (r / 2), y + h), fill=fill_color)
    draw_object.rectangle((x, y + r / 2, x + w, y + h - (r / 2)), fill=fill_color)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    2.4.2 绘制三角形 (对话的哪个尖尖)
    draw_object.polygon([
        (bg_height + space_length / 2, bg_height / 2),
        (bg_height + space_length, bg_height / 2 - space_length / 2),
        (bg_height + space_length, bg_height / 2 + space_length / 2),
    ], fill="#FFFFFF")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    2.4.3 绘制字体
    draw_object.text((bg_height + space_length + 15, (bg_height - 25) / 2 - 5 - 1),
                     text, fill=0, font=ImageFont.truetype(font_path, font_size))
    
    • 1
    • 2

    2.5 保存图片

    bg_img.save(save_path)
    
    • 1

    3. 效果展示

    在这里插入图片描述

    4. 成品代码

    from PIL import Image, ImageDraw, ImageFont
    
    def get_font_render_size(text, font_path, font_size):
        """
        :param text: 文字
        :param font_path: 字体路径
        :param font_size: 字体大小
        :return: tuple 宽高
        """
        canvas = Image.new('RGB', (2048, 2048))
        ImageDraw.Draw(canvas).text((0, 0),
                                    text, font=ImageFont.truetype(font_path, font_size))
        bbox = canvas.getbbox()
        return bbox[2] - bbox[0], bbox[3] - bbox[1]
    
    
    def main(text="Hello World", logo_path="logo.jpg", save_path="save.jpg",
             font_path="fonts/msyhl.ttc", font_size=25, space_length=20,
             bg_height=64):
        # 计算文字渲染后的长度
        text_width, text_height = get_font_render_size(text, font_path, font_size)
        # 定义背景宽度
        bg_width = text_width + space_length
        # 生成背景
        bg_img = Image.new(mode='RGB', size=(bg_width + 100, bg_height), color="#F5F5F5")
    
        # 读取头像文件,并绘制头像到背景图片
        logo = Image.open(logo_path, mode="r")
        logo = logo.resize((bg_height, bg_height))
        bg_img.paste(logo, (0, 0))
    
        # 绘制气泡
        ## 1. 绘制圆角矩形
        x, y, w, h, r = bg_height + space_length, 0, text_width + space_length * 1.5, bg_height, space_length
        fill_color = "#FFFFFF"
        draw_object = ImageDraw.Draw(bg_img)
    
        draw_object.ellipse((x, y, x + r, y + r), fill=fill_color)
        draw_object.ellipse((x + w - r, y, x + w, y + r), fill=fill_color)
        draw_object.ellipse((x, y + h - r, x + r, y + h), fill=fill_color)
        draw_object.ellipse((x + w - r, y + h - r, x + w, y + h), fill=fill_color)
    
        draw_object.rectangle((x + r / 2, y, x + w - (r / 2), y + h), fill=fill_color)
        draw_object.rectangle((x, y + r / 2, x + w, y + h - (r / 2)), fill=fill_color)
    
        ## 2. 绘制三角形 (对话的哪个尖尖)
        draw_object.polygon([
            (bg_height + space_length / 2, bg_height / 2),
            (bg_height + space_length, bg_height / 2 - space_length / 2),
            (bg_height + space_length, bg_height / 2 + space_length / 2),
        ], fill="#FFFFFF")
    
        ## 3. 绘制字体
        draw_object.text((bg_height + space_length + 15, (bg_height - 25) / 2 - 5 - 1),
                         text, fill=0, font=ImageFont.truetype(font_path, font_size))
    
        bg_img.save(save_path)
    
    
    if __name__=="__main__":
        main("Hello World") # 更改此处文字即可。
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
  • 相关阅读:
    慧差\畸变 zemax示例
    DERT:End-to-End Object Detection with Transformers
    基于Vue+Express+ElementUI+MySQL的简单数据库应用
    Spring Cloud Alibaba 分布式微服务高并发数据平台化(中台)思想+多租户saas设计的企业开发架构
    浅谈JVM(面试常考题)
    【微服务的集成测试】python实现-附ChatGPT解析
    大数据开发之数据仓库
    利用Git进行协作
    postgresql源码学习(35)—— 检查点⑤-检查点中的XLog清理机制
    HK32F030MF4P6的Linux GCC工具链开发环境
  • 原文地址:https://blog.csdn.net/okfang616/article/details/127883767