如何创建边界框并将文本放入其中?

Posted

技术标签:

【中文标题】如何创建边界框并将文本放入其中?【英文标题】:How can I create a bounding box and fit text into it? 【发布时间】:2022-01-05 04:16:58 【问题描述】:

我正在尝试将文本放入边界框。 基本上该函数的输入是:

    文本 -> 字符串(以','分隔的单词列表) width -> int(框的设置宽度)

示例 1:

** 如果所有文本都可以在边界框内并在一行中,则保持这种方式

输入: “测试,测试2,测试3”,100

它应该输出如下内容:

示例 2:

** 如果文本不能在一行中放入框内,则会使框变大(高度)并继续向下写一行

输入: "test, test2, test3, test4, test5", 100

它应该输出如下内容:

示例 3:

** 如果以',' 分隔的字符串列表中最长的字符串不能放入一行中的框中,则会使文本变小

输入: "wikipedia_is_long12345, test, test2, test3", 100

它应该输出如下内容:

另一个例子:

我想要一些提示/帮助, 谢谢。

【问题讨论】:

【参考方案1】:

我又尝试了一次,我做到了!

代码如下:

def fit_text(text, text_size, text_color, max_horizontal_chars, box_outline_color, box_background_color,
         box_outline_width, font_file, word_bank_outline, high_res):

"""
:param text: The text that needs to be fir inside the bounding box (words separated by ,)
:type text: str
:param text_size: The size of the text
:type text_size: int
:param text_color: The color of the text
:type text_color: Tuple(int, int, int) | str
:param max_horizontal_chars: The number of the max horizontal chars allowed in one line
:type max_horizontal_chars: int
:param box_outline_color: The color of the outline of the bounding box
:type box_outline_color: Tuple(int, int, int) | str
:param box_background_color: The color of the background of the bounding box
:type box_background_color: Tuple(int, int, int) | str
:param box_outline_width: The thickness of the outline of the bounding box
:type box_outline_width: int
:param font_file: The file of the font of the text
:type font_file: str
:param word_bank_outline: Whether there will be an outline or not
:type word_bank_outline: bool
:return: The image
:rtype: Image
"""
multiplier  = 2
text_size *= multiplier //2

# Replaces every ',' to '-' because the wrapper library will associate '-' as a separator and sorts by length
text = text.split(',')
text.sort(key=len, reverse=True)
text = ','.join(text).upper()
text = text.replace(',', '-')

# Changes the text size to fit the box if the longest word cannot fit in one line
font = ImageFont.truetype(font_file, text_size)
longest_word = sorted(text.split('-'), key=len)[-1]
if longest_word[0] == ' ':
    longest_word = longest_word[1:]
longest_word_size = font.getsize(longest_word)[0]
while longest_word_size >= 1100:
    longest_word = sorted(text.split('-'), key=len)[-1]
    if longest_word[0] == ' ':
        longest_word = longest_word[1:]
    longest_word_size = font.getsize(longest_word)[0]
    text_size -= 1
    font = ImageFont.truetype(font_file, text_size)

# Initializes the text wrapper
wrapper = textwrap.TextWrapper()
wrapper.max_lines = 3
wrapper.placeholder = '...'
wrapper.break_long_words = False
wrapper.width = max_horizontal_chars

# Wrap the text
text = wrapper.fill(text=text)


# Create a new image according to the size of the text
img = Image.new('RGBA', (font.getsize_multiline(text)[0], (font.getsize_multiline(text)[1]+20+(60 if high_res else 20)+box_outline_width+(text.count('\n')*10))), (0,0,0,0))

# Initializes the ImageDraw.Draw for the img so I can draw on it
draw = ImageDraw.Draw(im=img)

# If word_bank_outline is true it will draw a bunch or rectangles according to box_outline_width
if word_bank_outline:
    w, h = img.size
    for i in range(0, box_outline_width):
        shape = [(0 + i, 0 + i), (w - i, h - i)]
        draw.rectangle(shape, box_background_color, box_outline_color)

# Replaces every '-' back to ','
text = text.replace('-', ',').upper()

# Checks if the first char is ' ' if it is it will be cut out
if text[0] == ' ':
    text = text[1:]

# Draws the text onto the bounding box
draw.multiline_text(xy=(10 + (20 if high_res else 0), 0), text=text, font=font, fill=text_color, spacing=20)

return img

基本上实现它的主要因素是函数ttffont.getsize,它以像素为单位返回字符串的大小,因此我可以知道字符串的确切大小,我可以更准确地适应它,另一件事是库textwraper 将文本分成单独的行。

所以首先它会检查字符串中最长的单词是否可以容纳在边界框内,如果不是,它将循环并减小文本大小直到它适合 然后它会调用 textwrapper.fill 来分割文本,然后它只会在图像上绘制文本并绘制​​轮廓,然后它会返回图像。

最终结果:

【讨论】:

如果您确切指出解决问题的更改以及解决问题的原因,答案会更好。 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center。 感谢 Matthew 的反馈,我稍微改变了答案。现在答案好不好?我需要添加更多信息或其他任何内容吗?

以上是关于如何创建边界框并将文本放入其中?的主要内容,如果未能解决你的问题,请参考以下文章

如何在堆栈上创建大小为 x 的数组并将 scanf 值放入其中

如何在Word周围绘制边界框并将其保存在文件夹opencv python中

如何使用 JavaFX 将选择框、复选框和文本字段实现为一个按钮 [关闭]

如何在不添加新行的情况下在文本框的边界之外编写文本?

如何基于文本框创建数组表?

边界框创建者