展开

文章目录

修改历史

PIL图片添加文本时自动换行解决方案

2021-11-14 18:38:20 Python 69

简介

PIL是(Python Image Library)python的图片处理库,通过该库可以很方便的实现很多图像操作,比如在图片上添加文字、裁剪图片、缩放图片等等。

1. 使用PIL给图片添加文本

如简介中所述,PIL可以方便的在图片上添加文本,一般都是通过PIL中ImageFont类实现该功能,下面的示例代码就是简单的在图片上添加两段文本。

from PIL import Image, ImageFont, ImageDraw

texts = ['燕子去了,有再来的时候;杨柳枯了,有再青的时候;桃花谢了,有再开的时候。但是,聪明的,你告诉我,我们的日子为什么一去不复返呢?——是有人偷了他们罢:那是谁?又藏在何处呢?是他们自己逃走了罢:现在又到了哪里呢?',
         '我不知道他们给了我多少日子;但我的手确乎是渐渐空虚了。在默默里算着,八千多日子已经从我手中溜去;像针尖上一滴水滴在大海里,我的日子滴在时间的流里,没有声音,也没有影子。我不禁头涔涔而泪潸潸了。']

picture = 'congcong.png'
font_size = 24
font_file = 'simhei.ttf'
position = [34, 106]


def add_text():
    with Image.open(picture) as im:
        if im.mode.upper() == 'RGBA':
            layer = Image.new(
                'RGBA', im.size, color=(255, 255, 255, 255)
            )
            im = Image.alpha_composite(layer, im)
        draw = ImageDraw.Draw(im)

        font = ImageFont.truetype(font_file, font_size)
        for text in texts:
            draw.text(tuple(position), text, font=font, fill='black')
            position[1] += 25
        im.save('no_break.png', format='PNG')
        im.show()


add_text()

上面的示例代码很简单,首先通过texts列表定义了我们需要添加在图片上的文本,然后指定文本字体大小、字体文件路径以及开始添加文本的坐标点(x, y),因为有些PNG图片是带有透明通道的,因此先判断了图片的模式是否是RGBA模式,如果是则添加透明的涂层,如果不是则直接通过ImageDraw.draw()方法实例化出一个draw对象,这个draw对象就是在图片上添加文本的核心实例对象,通过draw实例中的text()方法将两段文本添加到图片上去,上述代码的运行结果如下图所示。可以看到当需要添加的文本长度过长时,PIL并不会自动进行换行,因此我们需要在文本过长时让其进行自动换行。

如果在你添加的文本中包含有回车符号(\n)PIL是会自动给你进行换行的,但是在实际开发中很多时候我们都是事先不知道文本的具体的长度的!

2. 跟字符数截取然后进行换行

在第一节的代码中我们可以清楚的知道在写到第21个字符的时候文本就所占用的像素长度就超过了图片的长度,因此我们可以通过21这个长度作为临界点来截取字符的长度然后换行重新书写,代码如下

from PIL import Image, ImageFont, ImageDraw

texts = ['燕子去了,有再来的时候;杨柳枯了,有再青的时候;hello, world,有再开的时候。But, you tell me '
         ',我们的日子为什么一去不复返呢?——是有人偷了他们罢:那是谁?又藏在何处呢?是他们自己逃走了罢:现在又到了哪里呢?',
         '我不知道他们给了我多少日子;但我的手确乎是渐渐空虚了。在默默里算着,八千多日子已经从我手中溜去;像针尖上一滴水滴在大海里,我的日子滴在时间的流里,没有声音,也没有影子。我不禁头涔涔而泪潸潸了。']

picture = 'congcong.png'
font_size = 24
font_file = 'simhei.ttf'
position = [34, 106]


def add_text():
    with Image.open(picture) as im:
        if im.mode.upper() == 'RGBA':
            layer = Image.new(
                'RGBA', im.size, color=(255, 255, 255, 255)
            )
            im = Image.alpha_composite(layer, im)
        draw = ImageDraw.Draw(im)

        font = ImageFont.truetype(font_file, font_size)
        for text in texts:
            index = 0
            while index < len(text):
                draw.text(tuple(position), text[index:index+21], font=font, fill='black')
                index += 21
                position[1] += 30
            position[1] += 20
        im.show()
        im.save('break_by_char_count.png', format='PNG')


add_text()

上面的代码跟第一节实例代码类似,只是在添加文本的时候自动截取了字符串的长度,然后重新换行书写,其结果如下图所示,但是我们还是会发现一些问题。如果当字符中包含有中英文的时候,因为中英文在同一种字体中一个字符所占用的长度明显是不一样的,可以看到第二行明显就没有对齐,对于这种情况我们可以使用第三节的解决方案。

3. 使用X轴坐标阈值自动换行

在PIL的ImageFont库中,可以通过font.font.get_size(text)来获取text文本所占用的像素长度,因此可以通过设置一个X轴的最大阈值来判断文本是否过长,示意图如下。

首先我们通过一些软件(Photo Shop或者GIMP等)获取底图的书写开始坐标以及书写最大X轴坐标,先在代码中设置最大阈值,然后通过getsize()方法获取将要书写的文本的所占用的像素点,我们可以事先设置一个假设的长度,比如这里的21(在实际中可以先测试一下字符的个数然后设置一个理想值)来截取文本的长度,实例代码如下

from PIL import Image, ImageFont, ImageDraw

texts = ['燕子去了,有再来的时候;杨柳枯了,有再青的时候;hello, world,有再开的时候。But, you tell me '
         ',我们的日子为什么一去不复返呢?——是有人偷了他们罢:那是谁?又藏在何处呢?是他们自己逃走了罢:现在又到了哪里呢?',
         '我不知道他们给了我多少日子;但我的手确乎是渐渐空虚了。在默默里算着,八千多日子已经从我手中溜去;像针尖上一滴水滴在大海里,我的日子滴在时间的流里,没有声音,也没有影子。我不禁头涔涔而泪潸潸了。']

picture = 'congcong.png'
font_size = 24
font_file = 'simhei.ttf'
position = [34, 106]
max_x = 520
guess_count = 21


def add_text(gc=guess_count):
    with Image.open(picture) as im:
        if im.mode.upper() == 'RGBA':
            layer = Image.new(
                'RGBA', im.size, color=(255, 255, 255, 255)
            )
            im = Image.alpha_composite(layer, im)
        draw = ImageDraw.Draw(im)

        font = ImageFont.truetype(font_file, font_size)
        for text in texts:
            index = 0
            while index < len(text):
                while font.font.getsize(text[index: index + gc])[0][0] + position[0] < max_x and index + gc < len(text):
                    gc += 1
                draw.text(tuple(position), text[index:index + gc], font=font, fill='black')
                index += gc
                position[1] += 30
                gc = guess_count
            position[1] += 20
        im.show()
        im.save('break_by_char_count.png', format='PNG')


add_text()

上述代码的关键地方在于最大X轴坐标、文本理想长度、以及getsize()方法,通过这三者就可以实现通过像素点进行自动换行了,效果图如下。

上面的代码源码都已开源在GitHub点击链接获取 https://github.com/weijiang1994/blog-demo/tree/main/pillow_font_break

当前共有0条评论