Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Roughly approximate the width of a string of text in Python?

Tags:

python

fonts

How would one, using Python, approximate the font width of a given string of text?

I am looking for a function with a prototype similar to:

def getApproximateFontWidth(the_string, font_name="Arial", font_size=12):
   return ... picas or pixels or something similar ...

I'm not looking for anything very rigorous, an approximation will be fine.

The motivation for this is that I am generating a truncated string in my webapp's backend and sending it to the front-end to be displayed. Most of the time the strings are lower case, but sometimes the strings are in all caps, making them very wide. If the string isn't properly trucated it looks ugly. I'd like to know how much to truncate the strings based on their approximate width. If it's off by 10% it's not a big deal, this is a cosmetic feature.

like image 359
speedplane Avatar asked Apr 15 '13 04:04

speedplane


People also ask

How do you get the visual length of a text string in Python?

Python len() function returns the length of the string.

How do you use width in Python?

width() This method is used to set or return the line thickness. Set the line thickness to width or return it.

How do you fix string width in Python?

Use a formatted string literal to format a number to a fixed width, e.g. result = f'{my_int:03d}' . The formatted string literal will format the number to the specified width by prefixing it with the necessary number of leading zeros.


1 Answers

Below is my simple solution, which gets you on the order of 80% accuracy, perfect for my purposes. It only works for Arial, only ascii, and it assumes 12 pt font, but it's probably proportional to other fonts as well.

def getApproximateArialStringWidth(st):
    size = 0 # in milinches
    for s in st:
        if s in 'lij|\' ': size += 37
        elif s in '![]fI.,:;/\\t': size += 50
        elif s in '`-(){}r"': size += 60
        elif s in '*^zcsJkvxy': size += 85
        elif s in 'aebdhnopqug#$L+<>=?_~FZT' + string.digits: size += 95
        elif s in 'BSPEAKVXY&UwNRCHD': size += 112
        elif s in 'QGOMm%W@': size += 135
        else: size += 50
    return size * 6 / 1000.0 # Convert to picas

And if you want to truncate a string, here it is:

def truncateToApproximateArialWidth(st, width):
    size = 0 # 1000 = 1 inch
    width = width * 1000 / 6 # Convert from picas to miliinches
    for i, s in enumerate(st):
        if s in 'lij|\' ': size += 37
        elif s in '![]fI.,:;/\\t': size += 50
        elif s in '`-(){}r"': size += 60
        elif s in '*^zcsJkvxy': size += 85
        elif s in 'aebdhnopqug#$L+<>=?_~FZT' + string.digits: size += 95
        elif s in 'BSPEAKVXY&UwNRCHD': size += 112
        elif s in 'QGOMm%W@': size += 135
        else: size += 50
        if size >= width:
            return st[:i+1]
    return st

Then the following:

>> width = 15
>> print truncateToApproxArialWidth("the quick brown fox jumps over the lazy dog", width) 
the quick brown fox jumps over the
>> print truncateToApproxArialWidth("THE QUICK BROWN FOX JUMPS OVER THE LAZY DOG", width) 
THE QUICK BROWN FOX JUMPS

When rendered, those strings are roughly the same width:

the quick brown fox jumps over the

THE QUICK BROWN FOX JUMPS

like image 167
speedplane Avatar answered Sep 22 '22 13:09

speedplane