Обтекание текста в PIL

Я использую PIL, чтобы нарисовать текст на изображении. Как бы я обернул строку текста. Это мой код:

text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."

image = Image.open("/tmp/background-image.jpg")
draw = ImageDraw.Draw(image)
font = ImageFont.truetype("/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf"), 50, encoding='unic')
draw.text((100, 100), text, font=font, fill="#aa0000")
image.save("/tmp/image.jpg")

Ответ 1

Вам нужно сначала разделить текст на строки нужной длины, а затем провести каждую линию по отдельности.

Вторая часть проста, но первая часть может быть довольно сложной, если делать шрифты с шириной ширины. Если используются шрифты с фиксированной шириной или если точность не так важна, вы можете просто использовать модуль textwrap, чтобы разделить текст в строки заданной ширины символа:

margin = offset = 40
for line in textwrap.wrap(text, width=40):
    draw.text((margin, offset), line, font=font, fill="#aa0000")
    offset += font.getsize(line)[1]

Ответ 2

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

import textwrap
texto = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
novo = textwrap.wrap(texto, width=20)
print(novo)

Результаты:

>>> 
['Lorem ipsum dolor', 'sit amet,', 'consectetur', 'adipisicing elit,', 'sed do eiusmod', 'tempor incididunt ut', 'labore et dolore', 'magna aliqua. Ut', 'enim ad minim', 'veniam, quis nostrud', 'exercitation ullamco', 'laboris nisi ut', 'aliquip ex ea', 'commodo consequat.', 'Duis aute irure', 'dolor in', 'reprehenderit in', 'voluptate velit esse', 'cillum dolore eu', 'fugiat nulla', 'pariatur. Excepteur', 'sint occaecat', 'cupidatat non', 'proident, sunt in', 'culpa qui officia', 'deserunt mollit anim', 'id est laborum.']

Возвращает список терминов в предыдущей строке, завернутый в соответствии с указанной вами шириной.

Ответ 3

Принятое решение переносит текст на основе фиксированного ограничения в 40 символов на строку, не принимая во внимание ширину поля (в пикселях) и размер шрифта. Это может легко привести к недостаточному или переполнению.

Вот лучшее решение - простой фрагмент кода для переноса текста с учетом измерения ширины шрифта:https://gist.github.com/turicas/1455973

Ответ 4

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

content_raw = 'AND WHAT ABOUT SOMETHING VERY LONG'
content = ''
for i in content_raw:
    if draw.textsize(content.split('\n')[-1])[0] > 30:
        content += '\n'
    content += i