生成文本图像

问题描述 投票:0回答:1

我正在生成包含特定文本的图像。生成带有文本的图像是没有问题的,其中所有文本标记都来自一种字体。我想随机加粗一些单词,这需要我使用(2种字体)常规和粗体。

这是我解决这个问题的方法:

  1. 我将文本拆分为单词。
  2. 随机创建一个字体蒙版,无论是常规还是粗体。
  3. 我将所有蒙版组合成一张图像,但是,因为它是一种从右到左的语言,所以我从右侧逐个添加蒙版。

问题:单词不在同一水平对齐线上!将不同的蒙版组合成一张图像是有问题的。

image containing arabic text

应该是这样的:

image containing arabic text

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")

python image fonts python-imaging-library arabic
1个回答
0
投票

以下代码生成此图像:

example output from code]

您同时使用静态字体和可变字体。可变字体需要指定变体的静态实例,否则它将使用在字体中找到的第一个实例。

我将采用基于另一个问题的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')

我已经手动布置了字符串组件,但这可以根据需要自动化。

© www.soinside.com 2019 - 2024. All rights reserved.