Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

fonts clipping with PIL

This image was created with PIL. See how the g's and the y's are cut off in this image? How can I prevent this?

http://img109.imageshack.us/img109/8874/screenshotep.png

The code that created this image is pretty straight forward (abbreviated):

import Image, ImageDraw, ImageFont

im = Image.new("RGBA", (200, 200), 'white')
draw = ImageDraw.Draw(im)

font = ImageFont.truetype("VeraSe.ttf", 12)

draw.text(
           (1, 1),
           " %s: " % "ggjyfFwe__",
           font=font,
           fill='black'
)

draw.text(
           (1, 30),
           " %s" % 15,
           font=font,
           fill='black'
)

im.show()

I tried it with a few different fonts, and it always gets clipped. Surprising;y, googleing "PIL font clipping" returns very few useful hits... I'm using python 2.6.4 and PIL 1.1.6 on Ubuntu 9.10

like image 368
priestc Avatar asked Dec 19 '09 18:12

priestc


2 Answers

Here's a late answer for this older question.

The problem appears to be that PIL and Pillow will clip the edges of rendered text. This most often shows on trailing wide characters and decenders (like 'y's). This can also appear on the top of some fonts. This has been a problem for at least ten years. It happens regardless of the size of the image on which text() is called. The conflict appears to choosing the bounding rectangle as "font.size * number_chars" instead of "whatever I actually need to render" and this occurs deep in the stack (_imagingft.c). Fixing this causes other problems, like lining up text rendered letter by letter.

Some solutions include:

  • Append a space to the end of your string. im.text(xy, my_text + ' ', ...)
  • For height issues, get the width of your text (font.getsize()), second render the text plus a good ascender and descender, chop the rendered text to the first reported width and the second actual height.
  • Use a different library such as AggDraw or pyvips.

This is referenced in various questions fonts clipping with PIL, PIL cuts off top of letters, Properly render text with a given font in Python and accurately detect its boundaries. These questions reference the same underlying issue but are not duplicates

like image 118
Charles Merriam Avatar answered Nov 19 '22 06:11

Charles Merriam


I couldn't solve this problem for some fonts using the approaches mentioned so far, so I ended up using aggdraw as a transparent replacement for PIL's text drawig methods.

Your code rewritten to aggdraw would look like:

import Image
import aggdraw

im = Image.new("RGBA", (200, 200), 'white')
draw = aggdraw.Draw(im)

# note that the color is specified in the font constructor in aggdraw
font = aggdraw.Font((0,0,0), "VeraSe.ttf", size=12, opacity=255)

draw.text((1, 1), " %s: " % "ggjyfFwe__", font) # no color here
draw.text((1, 30), " %s" % 15, font)

draw.flush() # don't forget this to update the underlying PIL image!

im.show()
like image 22
Florian Ledermann Avatar answered Nov 19 '22 07:11

Florian Ledermann