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

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

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

示例 1:

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

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

它应该输出如下内容:

示例 2:

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

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

它应该输出如下内容:

示例 3:

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

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

它应该输出如下内容:

另一个例子:

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

【问题讨论】:

    标签: python-3.x image-processing text-processing bounding-box


    【解决方案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 的反馈,我稍微改变了答案。现在答案好不好?我需要添加更多信息或其他任何内容吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-11-16
    • 1970-01-01
    • 1970-01-01
    • 2021-09-01
    • 2016-02-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多