Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Determining pixel height of a string with newlines in Pillow

I'm trying to draw text (that could be of any length depending on what the user inputs) on a blank image. I need to split the text in newlines to avoid creating too large images and I also need to create an image with the size related on how much characters the user inputs, avoiding any empty space. This is what i've come up with so far:

import PIL
import textwrap
from PIL import ImageFont, Image, ImageDraw

#Input text
usrInput = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sit amet scelerisque nulla. Pellentesque mollis tellus ut arcu malesuada auctor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Ut tristique purus non ultricies vulputate"
text = textwrap.fill(usrInput,50)

#font size, color and type
fontColor = (255,255,255)
fontSize = 40
font = ImageFont.truetype("/System/Library/Fonts/AppleGothic.ttf",fontSize)

#Image size and background color
background = (200,255,0)
#imgSize = font.getsize(text)
imgSize = ImageDraw.Draw.textsize(text, font)

def CreateImg ():
    img = Image.new("RGBA", imgSize, background)
    draw = ImageDraw.Draw(img)
    draw.text((0,0), text, fontColor, font)
    img.save("test.png")


CreateImg()

Now i've got a problem. If i use font.getsize to determine how big the image should be it works exactly as i want it, but only if the text doesn't break on a new line. If it does it gives me the height of a single line and the width of the full text without newlines. So i thought it probably it wasn't the right method and i decided to try ImageDraw.Draw.textsize (that should detect the lines and use ImageDraw.Draw.multiline_textsize if there are more than one), but it doesn't work and i get this error:

Traceback (most recent call last):
File "pil.py", line 17, in <module>
    imgSize = ImageDraw.Draw.textsize(text, font)
AttributeError: 'function' object has no attribute 'textsize'

What i'm doing wrong? I'm handling this issue well or there are better solutions?

like image 490
seesharp Avatar asked Oct 14 '15 13:10

seesharp


1 Answers

I think you got the order of the statements a bit mixed up.

Drawing text on an image that should be just big enough is a two step process: first, determine the text size, then create an image of that size.

This is a working example:

from PIL import ImageFont, Image, ImageDraw
import textwrap

# Source text, and wrap it.
userinput = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam sit amet scelerisque nulla. Pellentesque mollis tellus ut arcu malesuada auctor. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Ut tristique purus non ultricies vulputate"
text = textwrap.fill(userinput, 50)

# Font size, color and type.
fontcolor = (255, 255, 255)
fontsize = 40
font = ImageFont.truetype("/System/Library/Fonts/AppleGothic.ttf", fontsize)

# Determine text size using a scratch image.
img = Image.new("RGBA", (1,1))
draw = ImageDraw.Draw(img)
textsize = draw.textsize(text, font)

# Now that we know how big it should be, create
# the final image and put the text on it.
background = (200, 255, 0)
img = Image.new("RGBA", textsize, background)
draw = ImageDraw.Draw(img)
draw.text((0, 0), text, fontcolor, font)

img.show()
img.save("seesharp.png")
like image 147
Michiel Overtoom Avatar answered Oct 15 '22 08:10

Michiel Overtoom