Source code for tcutility.report.character
import os
from tcutility import cache, log
def _load_data() -> dict:
"""
Load character width data. It is stored in a file where each line is formatted as:
{font} {character} {width}
Font names that originally contained spaces, for example "Times New Roman", will have the spaces replaced
by underscores.
Returns:
We return a nested dictionary with the first key being the font and the nested key the characters.
The widths are given in pixel sizes and are for font-size 1.
"""
with open(os.path.join(os.path.split(__file__)[0], "_char_widths.txt"), encoding="utf-8") as widths:
lines = widths.readlines()
ret = {}
for line in lines:
# we split each line into parts by white space
parts = line.split()
# if there are only 2 parts, that means that the character was a space
if len(parts) == 2:
font, width = parts
character = " "
else:
font, character, width = line.split()
# fonts that contain spaces in the name had the spaces replaced by underscores
# here we restore the original spaces
font = font.replace("_", " ")
width = float(width)
ret.setdefault(font, {})
ret[font][character] = width
return ret
widths = _load_data()
[docs]
@cache.cache
def get_pixel_width(character: str, font: str = "calibri", font_size: float = 11) -> float:
"""
Get the pixel width of a character for a given font and font-size.
For this we need to interpolate the pixel width between two reference values.
In the _char_widths.txt file you will find for each font a set of character pixel widths for font-size 1.
We then simply multiply the 1-width value by the desired value to get the correct pixel width.
See
Args:
character: the character to get the pixel width for.
font: the font family that is used.
font_size: the font-size to get the pixel width at.
"""
if font not in widths.keys():
raise ValueError(f"Could not find font {font}.")
return widths[font][character] * font_size
[docs]
def text_width(text: str, font: str = "calibri", font_size: float = 11, mode: str = "pixels") -> float:
"""
Get the width of a string for a given font and font size.
Args:
text: the object to determine the length for.
Will be cast to a string before calculating width.
font: the font family that is used.
font_size: the font-size to get the pixel width at.
mode: the width-mode. Can be 'excel' or 'pixels'.
Returns:
The width of the text for a certain font and font size.
If mode is 'excel' we pad it with 8 pixels and then divide by 7.6 (i.e. standard excel char width).
"""
if font not in widths.keys():
log.error(f"Could not find font {font}. Defaulting to Calibri.")
font = "calibri"
pixels = sum(get_pixel_width(char, font, font_size) for char in str(text))
if mode == "excel":
return (pixels + 8) / 7.6
if mode == "word":
return (pixels + 8) / 7.6
return pixels
if __name__ == "__main__":
print(text_width("this is a test text", font="test"))