Reputation: 81
I'm working on a problem that requires good precision pixel by pixel, so I need to have the ability to manipulate text in more ways than what PIL provides. Especially with regard to kerning. There is a feature that allows you to disable kerning, but not control the amount.
This problem was made more challenging because of bugs in PIL that relate to accurately measuring the size of text. There are many posts about this problem but the most useful information is a SO post here, How to get the font pixel height using PIL's ImageFont class? and a blog article, How to properly calculate text size in PIL images
Upvotes: 0
Views: 813
Reputation: 81
My code is for my own use but if someone is having similar issues, I'm sure that it can easily be adapted for your own needs.
My key functions are:
def get_text_width(text_string, font):
return font.getmask(text_string).getbbox()[2]
def kern(name, draw_object, y, space, font, fill):
chars = [char for char in name]
total_width = 0
for char in chars:
width_text = get_text_width(char, font)
total_width += (width_text + int(space))
__, height_text = draw_object.textsize(name, font)
__, offset_y = font.getoffset(name)
height_text += offset_y
width_adjuster = 0
for char in chars:
width_text = get_text_width(char, font)
top_left_x = (473 / 2 - total_width / 2) + width_adjuster
top_left_y = (40 / 2 - height_text / 2) + y
xy = top_left_x, top_left_y
width_adjuster += width_text + int(space)
print(f"char:{char},width_text:{width_text},xy:{xy},width_adjuster:{width_adjuster}")
draw_object.text(xy, char, font=font, fill=fill)
It gives a nice output below. However, it's not entirely precise. The number of pixels between letters will vary slightly with different fonts. I have not found a way to standardize this, so I've just accepted the fact when I enter a value for kerning into my GUI, it is just a scalar relative to the font, not the number of pixels
Upvotes: 1