Поскольку вы имеете дело со шрифтами, вам нужно знать о методе getsize
.Это поможет вам понять, как разбить текст.
Предположим, у вас есть строка:
def get_a_string():
return "here is some string"
text = get_a_string()
Теперь у вас также есть изображение, которое имеет ширину и высоту:
bgcolor = (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
img = Image.new('RGB', (300, 200), color=bgcolor)
# Read the size tuple, unpack into height, width
img_height, img_width = img.size
Если текст слишком длинный, его следует сократить:
font = ImageFont.truetype("Arial.ttf", 14)
text_height, text_width = font.getsize(text)
if text_width > (0.95 * img_width):
# Not enough room. Break the text
lines = split_by_words()
Как его можно сократить?Сначала попробуйте использовать границы слов:
def split_by_words(text):
text = text.rstrip() # Strip trailing whitespace
words = text.split()
lines = []
while words:
# I use None instead of '' to allow for leading spaces
line = None
for i, word in enumerate(words):
new_line = word if line is None else line + ' ' + word
(h, w) = font.getsize(new_line)
if w > img_width:
# New line won't fit? Break, keeping old line value.
break
else:
# Still fits? Save it!
line = new_line
if i == 0:
# First word was too long. Try character-by-character
lines.extend(split_by_character(words[0]))
# TODO: You might want to put lines[-1] into words[0] to join long first word
# remainder with short second word.
words = words[1:]
else:
lines.append(line)
words = words[i:]
return lines
Это будет вызывать getsize
несколько раз, что может быть дорого.(Или нет: если вы генерируете мемы из фотографий кошек, это, вероятно, не будет стоить дорого, поскольку текст короткий. Если вы пишете текстовый процессор, будьте осторожны!)
Альтернативой может быть вычислениеразмер исходного текста, затем предположим, что все символы имеют одинаковую ширину, и сделайте предположение о том, где разделение должно быть основано на отношении размера изображения к размеру текста:
th, tw = font.getsize(text)
ih, iw = img.size
ratio = iw / tw # 300 / 622, say
split_pos = int(len(text) * ratio) # 0.51 * text len, about halfway along
line1 = text[:split_pos]
if font.getsize(line1) > iw:
while True:
split_pos -= 1
line1 = line1[:-1]
if font.getsize(line1) <= iw:
break
else: # too short
while True:
line1 += text[split_pos]
if font.getsize(line1) > iw:
line1 = line1[:-1]
break
split_pos += 1
Обратите внимание, что это символна основе, а не на основе слов, так что это отстой.А поскольку большинство шрифтов пропорциональны, соотношение, вероятно, неправильное.Вы можете настроить его, используя некоторые эвристические методы, включая встроенный набор допущений по ширине.(просто вычислите ширину всех букв за один раз, сохраните их в таблице и предположите, что все шрифты используют эту ширину - все еще неправильно, но обычно это лучшее приближение, чем метод отношения, и быстрее!)