使用 PIL 在同一行上写不同的文本字体

Writing different text fonts on the same line using PIL

我试图在同一行上使用两种不同的字体在图像上写价格,一种用于数字,一种用于货币符号(在本例中为 €),所以我想知道什么是使用 PIL 的正确方法。我目前正在尝试的是在第一个字体上使用 font.getsize(),并将 getsize 的 X 轴结果添加到文本的坐标以获得写入符号所需的偏移量:

d_price = "248"

d_price_font = ImageFont.truetype("Gotham Black Regular.ttf", 58)
symbol_font = ImageFont.truetype("Myriad Pro Regular.ttf", 70)

d_price_size = d_price_font.getsize(d_price)
d_price_coords = (677, 519)

draw.text(d_price_coords, d_price, (0, 255, 255), font=d_price_font)
symbol_coords = (d_price_coords[0] + d_price_size[0], d_price_coords[1])
draw.text(symbol_coords, "€", (255, 255, 255), font=symbol_font)

这似乎行得通,但是每次我想在价格旁边写一个符号时,这都需要我计算文本的大小,还要调整字体大小,这与我的不同使用价格。

我认为您的方法没问题,但是有一种更好的代码编写方法可以避免重复,并且可以更轻松地添加更多不同字体的文本:

from PIL import ImageFont, Image, ImageDraw


def draw_text_in_font(d: ImageDraw, coords: tuple[int, int], 
                      content: list[tuple[str, tuple[int, int, int], str, int]]):
    fonts = {}
    for text, color, font_name, font_size in content:
        font = fonts.setdefault(font_name, ImageFont.truetype(font_name, font_size))
        d.text(coords, text, color, font)
        coords = (coords[0] + font.getsize(text)[0], coords[1])


with Image.open("white.png") as im:
    draw = ImageDraw.Draw(im)

    draw_text_in_font(draw, (10, 10), [
        ('248', (255, 255, 0), 'C:/Windows/Fonts/Consola.ttf', 70),
        ('€', (255, 0, 255), 'C:/Windows/Fonts/Arial.ttf', 56)
    ])

    im.show()

这只是将您所做的一切捆绑在一个相当易读的函数中,同时调用它也非常清晰。您可以使用其他字体串接更多文本,并且在创建字体后它会重复使用该字体。

为内容使用 list[dict[str, Any]] 或什至为其定义数据 class 可能会更好,这样您可以在代码中更清楚地说明您的值是什么重新传递给 draw_text_in_font,但想法是一样的。

此外,如果您改为编写 class,则可以缓存您在 class 属性中使用的字体,以避免每次编写文本时都创建它们,但这只是细节。

请注意,我喜欢将类型明确化,因为它可以帮助使用代码的任何人在像样的编辑器或 IDE 中提供正确的参数。但这可能会起到同样的作用,只是对编码器来说不太好:

def draw_text_in_font(d, coords, content):
    fonts = {}
    for text, color, font_name, font_size in content:
        font = fonts.setdefault(font_name, ImageFont.truetype(font_name, font_size))
        d.text(coords, text, color, font)
        coords = (coords[0] + font.getsize(text)[0], coords[1])