我正在生成包含特定文本的图像。生成带有文本的图像是没有问题的,其中所有文本标记都来自一种字体。我想随机加粗一些单词,这需要我使用(2种字体)常规和粗体。
这是我解决这个问题的方法:
问题:单词不在同一水平对齐线上!将不同的蒙版组合成一张图像是有问题的。
应该是这样的:
from PIL import Image, ImageFont
import random
font_size = 60
font_bold_file = "fonts/Cairo/static/Cairo-Bold.ttf"
font_regular_file = "fonts/Cairo/Cairo-VariableFont_slnt,wght.ttf"
text_color = (0, 0, 0, 255)
font_regular = ImageFont.truetype(font_regular_file, size=font_size)
font_bold = ImageFont.truetype(font_bold_file, size=font_size)
text = "أبت أ ري عالم"
total_x = 0
total_y = 0
segments = []
for w in text.split(" "):
mask = None
if random.random() < 1:
mask = font_regular.getmask(w + " ", "L")
else:
mask = font_regular.getmask(w + " ", "L")
segments.append( (mask, mask.size[0]) )#
total_x += mask.size[0]
total_y = max(total_y, mask.size[1])
background_img = Image.new(mode="RGBA", size=(total_x, total_y), color=(255, 255, 0, 255))
acc_widths = 0
for seg in segments:
mask = seg[0]
width = seg[1]
pivot_x = total_x - acc_widths - width
acc_widths += width
mask_req = (pivot_x, 0, pivot_x + width, mask.size[1] )
background_img.im.paste(text_color, mask_req, mask)
background_img.save("pic.png")
以下代码生成此图像:
]
您同时使用静态字体和可变字体。可变字体需要指定变体的静态实例,否则它将使用在字体中找到的第一个实例。
我将采用基于另一个问题的answer的替代方法,而不是使用掩码,并为其添加可变字体支持。
首先,我定义一个函数来获取图像使用的尺寸。这是基于另一个答案。由于使用了不止一种字体粗细,因此我根据主要字体确定了尺寸,并添加了一个模糊因子以适应变化。
from PIL import Image, ImageFont, ImageDraw
def get_text_dimensions(text_string, font, fudge=0):
ascent, descent = font.getmetrics()
text_width = font.getmask(text_string).getbbox()[2]
text_height = font.getmask(text_string).getbbox()[3] + descent
return (text_width + fudge, text_height)
在此示例中,我将仅使用可变字体,因为它包含常规和粗体实例。不需要两种单独的字体。
如果需要,定义模糊因子。
我将单词分成一个列表,反转列表,因为我正在处理 RTL 文本,但按视觉顺序处理它。
然后我计算空间的水平长度以供稍后调整。
text = "أبت أ ري عالم"
font_file = '~/Library/Fonts/Cairo-VariableFont_slnt,wght.ttf'
font_size = 60
dimension_fudge = 10
tokens = text.split()[::-1]
text_font = ImageFont.truetype(font_file, font_size)
# text_font.get_variation_names()
text_font.set_variation_by_name('Regular')
space = text_font.getlength('\u0020')
然后,我从
answer调整
draw_text_in_font()
,添加可变字体、方向和语言支持,然后调整坐标以考虑空白。
该功能缺少的一个方面是控制所应用的 opentype 功能的能力。
def draw_text_in_font(d: ImageDraw, coords: tuple[int, int],
content: list[tuple[str, tuple[int, int, int], str, int, str, str, str]]):
fonts = {}
for text, color, font_name, font_size, variant, dir, lang in content:
font = fonts.setdefault(font_name, ImageFont.truetype(font_name, font_size))
font.set_variation_by_name(variant)
d.text(coords, text, color, font, direction=dir, language=lang)
coords = (coords[0] + font.getlength(text) + space, coords[1])
然后计算图像尺寸并生成背景图像,然后使用
draw_text_in_font()
将文本添加到图像中。
dimensions = get_text_dimensions(text, text_font, dimension_fudge)
background_img = Image.new(mode="RGBA", size=(dimensions[0], dimensions[1]), color=(255, 255, 0, 255))
draw = ImageDraw.Draw(background_img)
draw_text_in_font(draw, (0, 0), [
(tokens[0], (0, 0, 0), font_file, font_size, 'Regular', 'rtl', 'ar'),
(tokens[1], (0, 0, 0), font_file, font_size, 'Bold', 'rtl', 'ar'),
(tokens[2], (0, 0, 0), font_file, font_size, 'Regular', 'rtl', 'ar'),
(tokens[3], (0, 0, 0), font_file, font_size, 'Regular', 'rtl', 'ar')
])
background_img.save('output.png')
我已经手动布置了字符串组件,但这可以根据需要自动化。