0

I am getting different values for text measurements (i.e. pixel width of a line of text) when using tkinter.font.Font and PIL.ImageFont.FreeTypeFont objects.

Example Code (python 3)

import tkinter as tk
from tkinter.font import Font
import shlex, subprocess
import PIL

"""
Get the path of the font to use with PIL 
"""
def get_font_path(fname):
    command_line = str('fc-match -f "%{file}\n" '+fname)
    args = shlex.split(command_line)
    p=subprocess.check_output(args, stderr=subprocess.STDOUT)
    fontpath = p.decode('UTF-8').splitlines()[0]
    print(fontpath)
    return fontpath



fname = 'Courier'
fsize = 14
sampletxt = "Am I a beagle?"

fontpath = get_font_path(fname)
pilfont = PIL.ImageFont.FreeTypeFont(font=fontpath, size=fsize)
print(f'width, height: {pilfont.getsize(sampletxt)}')

The output from the above PIL measurement.

/usr/share/fonts/type1/texlive-fonts-recommended/pcrr8a.pfb
width, height: (112, 14)

Example Code Continued..

"""
The Tkinter measurements
"""

##root = tk.Tk() #Don't need this apparently 
tkfont = Font(family="Courier", size=fsize)
print(f'width, height: {(tkfont.measure(sampletxt), tkfont.metrics("linespace"))}')

tkfont.actual()

The output from the above Tkinter measurement:

width, height: (168, 17)

{'family': 'gothic',
 'size': 14,
 'weight': 'normal',
 'slant': 'roman',
 'underline': 0,
 'overstrike': 0}

These values are different. Obviously, tkinter is using a different font, but from where? Making Tkinter use the same font that is specified in the PIL object may fix this, but I cannot determine how tkinter loads or uses fonts.

I've looked at this related truly custom font in tkinter question, but I am using debian (ubuntu) not Windows.

Here are some more tkinter font properties if it helps you help me.

tkinter.font.families() 

## OUTPUT:

('fangsong ti',
 'fixed',
 'clearlyu alternate glyphs',
 'courier 10 pitch',
 'open look glyph',
 'bitstream charter',
 'song ti',
 'open look cursor',
 'newspaper',
 'clearlyu ligature',
 'mincho',
 'clearlyu devangari extra',
 'clearlyu pua',
 'clearlyu',
 'clean',
 'nil',
 'clearlyu arabic',
 'clearlyu devanagari',
 'gothic',
 'clearlyu arabic extra')
tkinter.font.names()

##OUTPUT:

('TkCaptionFont',
 'TkSmallCaptionFont',
 'TkTooltipFont',
 'font308',
 'TkFixedFont',
 'TkHeadingFont',
 'font310',
 'TkMenuFont',
 'TkIconFont',
 'TkTextFont',
 'TkDefaultFont')

UPDATE:

I have tried using a Tkinter font and then using the corresponding font file to create a PIL FreeType font object and the measurements are still different....

I am pretty stumped.

text = "Where are my beards?"

### PIL Measurement ###

# The location of the fontfile corresponding to 'courier 10 pitch'
fontpath = '/usr/share/fonts/X11/Type1/c0419bt_.pfb'

font = ImageFont.FreeTypeFont(font=fontpath, size=80)

im = Image.new("RGBA", (1092, 1456), (0, 0, 0))
draw = ImageDraw.Draw(im)
draw.multiline_text((0,0), text, (255, 255, 255), font=font)
multi_size = draw.multiline_textsize(text, font=font)
print(f"multi size: {multi_size}\n")
w,h = font.getsize_multiline(text)
im.close()
del im
print(f'Width: {w}, Height: {h}\n')
#print font name
print(font.getname())

Output of PIL measurement:

multi size: (960, 69)

Width: 960, Height: 69

('Courier 10 Pitch', 'Regular')

Tkinter Font Measurement

fname = 'courier 10 pitch'
font = tkFont.Font(family=fname, size=80)

(w,h) = (font.measure(text),font.metrics("linespace"))
print(f'Width: {w}, Height: {h}\n')
print(f'{ sorted([k, v] for k,v in font.actual().items()) }')

Ouput of Tkinter Measurement:

Width: 1280, Height: 124

[['family', 'courier 10 pitch'], ['overstrike', 0], ['size', 80], ['slant', 'roman'], ['underline', 0], ['weight', 'normal']]

The Width: 960, Height: 69 of the PIL measurement vs. Width: 1280, Height: 124 of the Tkinter measurement is quite a difference.

I believe the Tkinter measurement is the accurate one, but I cannot rely on using Tkinter display on a headless server (for example).

If I am not mistaken, these two measurements should be identical because I have used the same font file for both.

Any ideas?

unbutu
  • 125
  • 2
  • 9
  • ***"use the same font that is specified in the `PIL` object may fix this"***: Have you tried this? – stovfl Jan 19 '20 at 12:33
  • @stovfl: This requires being able to load external fonts into Tkinter which I have looked at and [linked in my question](https://stackoverflow.com/questions/11993290/truly-custom-font-in-tkinter) Unfortunately, the method outlined works for Windows based machines where I am using Debian/Ubuntu. I will post an update once I figure things out a bit more. I do not know much about fonts, and it seems there is a lot to learn – unbutu Jan 24 '20 at 17:50
  • I really wanted to know if there is a straight forward way of getting a font path from a tkinter font.Font – rodrigombs Jan 18 '22 at 03:48

0 Answers0