我正在生成包含特定文本的图像。生成带有文本的图像是没有问题的,其中所有文本标记都来自一种字体。我想随机粗体一些单词,这需要我使用(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")
问题在于,正在为每个单词创建一个独立的蒙版,而没有考虑阿拉伯文字的基线对齐方式。阿拉伯语是一种脚本,某些字符连接在基线上方或下方。当前的方法将每个单词视为一个独立的单元,导致了不正确的垂直对齐方式。
以下是如何解决此问题的步骤:
-
计算最大基线:
在为各个单词创建蒙版之前,循环遍历文本中的所有单词,并使用
font.getbbox(word)
找到每个单词的边界框。找到所有边界框中y
值(基线)的最大值。这将为提供用于对齐所有单词的公共基线。 -
使用公共基线创建蒙版:
生成每个单词的蒙版时,使用
font.getmask2(word, mode='L')
方法。getmask2()
方法返回蒙版和边界框信息。使用步骤 1 中计算的公共基线,将单词蒙版垂直放置在图像中。 - 从右到左组合蒙版: 当前的方法已经正确地从右到左组合蒙版,因此可以继续使用该方法。
以下是更新后的代码:
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 = "أبت أ ري عالم"
# Calculate maximum baseline
max_baseline = 0
for word in text.split(" "):
bbox = font_regular.getbbox(word)
max_baseline = max(max_baseline, bbox[1])
total_x = 0
total_y = max_baseline # Use maximum baseline for image height
segments = []
for word in text.split(" "):
mask = None
if random.random() < 1:
mask, bbox = font_regular.getmask2(word + " ", "L")
else:
mask, bbox = font_bold.getmask2(word + " ", "L")
segments.append((mask, bbox[2])) # Store width of the word
total_x += bbox[2] # Use actual word width for positioning
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, max_baseline - bbox[1], pivot_x + width, max_baseline - bbox[1] + mask.size[1])
background_img.im.paste(text_color, mask_req, mask)
background_img.save("pic.png")
这段代码首先计算所有单词的公共基线,然后使用
getmask2()
方法和公共基线将每个单词放置在正确的位置。这可以确保所有单词都正确对齐到公共基线上,从而解决垂直对齐问题。