Search code examples
pythonpython-imaging-library

How do I write a multi-line text in pillow?


I am trying to convert one long text to multiline text. I wrote some code, and it mostly works. But I have some problems in line width calculation. Because the lines getting shorter and shorter. Probably caused by lastCalculatedWidth or resultTextLength or both of them. I tried a lot of things but I'm very confused and I want to solve this as soon as possible, I would appreciate it if you could help me.output-image

text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec augue leo, pulvinar maaaıs sagittis sit amet, tristique viverra mauris. Sed mauris quam, faucibus id pretium non, varius eget leo."
result_text = ""
messageBreakLineIndexes = []
calculatedWords = 0
messageLineWidth = draw.textlength(text, font=font)
resultTextLength = 0
lastCalculatedWidth = 0
calculationSwitch = True

while calculatedWords < len(text.split()):
    result_text += text.split()[calculatedWords] + " "
    resultTextLength += draw.textlength(text.split()[calculatedWords], font=font)
    if resultTextLength > img.width - 60:
        result_text = result_text.rstrip()
        result_text = result_text.rsplit(" ", 1)[0]

        messageBreakLineIndexes.append(len(result_text))
        calculatedWords -= 1
        
        resultTextLength -= draw.textlength(result_text.rstrip(), font=font) - lastCalculatedWidth
        lastCalculatedWidth = draw.textlength(result_text.rstrip(), font=font)
    calculatedWords += 1

print(messageBreakLineIndexes)
for i in range(len(messageBreakLineIndexes)):
    index = messageBreakLineIndexes[i]
    result_text = result_text[:index+i] + "\n" + result_text[index+i:]
draw.text(text_position, result_text, font=font, fill=text_color)

Solution

  • i merged codes with mine and @Attersson's answer because draw.textlength cannot work with \n. It's look like fine now.enter image description here

    text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec augue leo, pulvinar maaaıs sagittis sit amet, tristique viverra mauris. Sed mauris quam, faucibus id pretium non, varius eget leo."
    result_text = ""
    messageBreakLineIndexes = []
    resultTextLength = 0
    
    words = text.split()
    
    # Iterate over the words directly as an iterable, not by len
    for word in words:
        # Check the width of the current line plus the next word
        word_width = draw.textlength(word, font=font)
        if resultTextLength + word_width <= img.width - 60:
            # If the line isn't too wide, add the word to the line
            result_text += word + " "
            resultTextLength += word_width + draw.textlength(" ", font=font)  # Add space width
        else:
            # If the line is too wide, break the line
            result_text = result_text.rstrip()
            messageBreakLineIndexes.append(len(result_text))
            result_text += word + " "
            resultTextLength = word_width + draw.textlength(" ", font=font)  # Reset line width
    
    for i in range(len(messageBreakLineIndexes)):
        index = messageBreakLineIndexes[i]
        result_text = result_text[:index+i] + "\n" + result_text[index+i:]
    draw.text(text_position, result_text, font=font, fill=text_color)