Рубрики
Без рубрики

Как Haptik генерирует изображения на лету с Python – часть 2

Рисование многострочного текста с подушкой. Теги с Python, Showdev, WebDev, Automation.

В первом посте этой серии я представил вам основы рисунка текста в Python, добавив текст приветствия на изображении. Я также подчеркнул примеры того, как я дополнительно расширил эту функциональность для создания некоторых сложных изображений на работе. Если вы еще этого не прочитали первую часть этой серии (как Haptik генерирует изображения на лету с Python), я рекомендую сначала взглянуть на него, чтобы лучше понять этот пост.

На данный момент мы знаем, как нарисовать текст, изменить шрифт и поместить текст на изображении. В этом посте мы узнаем, как нарисовать многострочный текст, а также обсудить проблемы этого.

Многослойный текст

Часто при создании изображений мы сталкиваемся с ситуациями, когда текст не подходит в одну строку. Подушка Python здесь не полезена, так как она не нарисовать автоматически и нажимает текст на новую строку. Чтобы сделать это вручную, нам нужно рассчитать ширину и высоту текста.

С помощью ширины текста мы определяем, когда нам нужно перейти к следующей строке и с высотой текста, мы можем понять, сколько места должно оставить между двумя линиями:

Идея состоит в том, чтобы разделить длинные предложения на несколько более коротких предложений и нарисовать каждый из них, один на один на правильных позициях, тем самым делая его как многострочный текст. Чтобы разделить более длинную строку, мы будем использовать функцию подушки для расчета размера текста, переданного ему как один из параметров.

Рассчитайте текст ширины

Для удобства я создал метод text_wrap () Чтобы объяснить линейную логику:

from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw

def text_wrap(text, font, max_width):
    lines = []
    # If the width of the text is smaller than image width
    # we don't need to split it, just add it to the lines array
    # and return
    if font.getsize(text)[0] <= max_width:
        lines.append(text) 
    else:
        # split the line by spaces to get words
        words = text.split(' ')  
        i = 0
        # append every word to a line while its width is shorter than image width
        while i < len(words):
            line = ''         
            while i < len(words) and font.getsize(line + words[i])[0] <= max_width:                
                line = line + words[i] + " "
                i += 1
            if not line:
                line = words[i]
                i += 1
            # when the line gets longer than the max width do not append the word, 
            # add the line to the lines array
            lines.append(line)    
    return lines


def draw_text(text):    
    # open the background file
    img = Image.open('background.png')

    # size() returns a tuple of (width, height) 
    image_size = img.size 

    # create the ImageFont instance
    font_file_path = 'fonts/Avenir-Medium.ttf'
    font = ImageFont.truetype(font_file_path, size=50, encoding="unic")

    # get shorter lines
    lines = text_wrap(text, font, image_size[0])
    print lines # ['This could be a single line text ', 'but its too long to fit in one. ']


if __name__ == __main__:
    draw_text("This could be a single line text but its too long to fit in one.")

Эта функция ожидает трех параметров – текст рисовать, ImageFont экземпляр класса и ширина фонового изображения, на котором можно нарисовать текст.

Логика довольно простая:

  • Проверьте, если предложение может вписаться в одну строку, просто верните его без разделения, иначе:
  • Разделить предложение, используя пробелы, чтобы извлечь слова в нем
  • Создавайте более короткие строки, добавляя слова, в то время как ширина меньше, чем ширина изображения

Когда мы запускаем этот скрипт, он возвращает массив, содержащий 2 более коротких строки, которые вписываются в ширину фонового изображения.

Чтобы нарисовать эти строки на изображении, мы должны рассчитать правильное вертикальное положение каждой строки.

Рассчитать высоту текста

Всякий раз, когда мы пишем текст, существует равное количество пространства между двумя линиями. Например, в этом посте строчки имеют постоянные пробелы между ними. При создании этой библиотеки я столкнулся с проблемой различных пробелов с большим количеством входного текста:

text = "This could be a single line text but it can't fit in one line."
lines = text_wrap(lines, font)

for line in lines:
    print font.getsize(line)[1]

# Output
# 62
# 51

Найти правильную высоту для символов, таких как G, J, P, Q, Y которые нарисованы ниже Базовая линия и B, D, F, H, K, L которые нарисованы выше Медиана немного утомительно из-за различных высот.

Лучший способ получить правильную высоту текста – просто рассчитать общую высоту «HG». Этот трюк работает, потому что h и g Накройте диапазон высоты всех английских символов.

Для языков, кроме английского, вам, возможно, придется использовать разные символы вместо H & g .

text = "This could be a single line text but it can't fit in one line."
lines = text_wrap(lines, font)

line_height = font.get_size('hg')[1]
print line_height

# Output
# 62

Поскольку у нас есть наши обернутые/короткие линии, а также высота текста, мы можем нарисовать их на изображении. Мы можем сделать это, поддерживая ссылку на вертикальное положение ранее нарисованной линии, а затем добавляя к нему высоту линии для расчета вертикального положения новой линии:

text = "This could be a single line text but its too long to fit in one."
lines = text_wrap(text, font, image_size[0])
line_height = font.getsize('hg')[1]

x = 10
y = 20
for line in lines:
    # draw the line on the image
    draw.text((x, y), line, fill=color, font=font)

    # update the y position so that we can use it for next line
    y = y + line_height
# save the image
img.save('word2.png', optimize=True)

Это выкроет так, как это:

Текст на последних изображениях выглядит намного лучше и читабелен. На Хаптик Мы верим в эксперименты и выясняя наилучший способ решить проблемы. Вышеуказанное является одним из таких примеров. В моем следующем посте в блоге я буду писать о том, как в центре Выровнять текст горизонтально и вертикально в изображении с помощью Python.

Думаю, я сделал хорошую работу? Позвольте мне знать в комментариях ниже.

Этот пост был изначально написан на Haptik Tech Blog Отказ

Оригинал: “https://dev.to/vinayjn/how-haptik-generates-images-on-the-fly-with-python—part-2-2fo9”