736f5f6163636f756e74
736f5f6163636f756e74

Reputation: 81

How to kern text in PIL

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

Answers (1)

736f5f6163636f756e74
736f5f6163636f756e74

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

kerning values 2 and 5

Upvotes: 1

Related Questions