PiSupply / PaPiRus

Resources for PaPiRus ePaper eInk displays
https://www.pi-supply.com/product/papirus-epaper-eink-screen-hat-for-raspberry-pi/
Other
345 stars 88 forks source link

Center Text of Different Fonts and Sizes? #218

Closed ahnyerkeester closed 3 years ago

ahnyerkeester commented 3 years ago

Any suggestions on how to center text on the screen no matter the font or text size or font size? I've been fiddling around for a while and can't quite nailed it.

tvoverbeek commented 3 years ago

Use the functions from the PIL library to get the size of the text and position the text box accordingly. See e.g. https://levelup.gitconnected.com/how-to-properly-calculate-text-size-in-pil-images-17a2cc6f51fd

ahnyerkeester commented 3 years ago

Again, thanks Ton! This is some coding I had been googling but never found. It is close to what I'd written myself. I'm pretty proud of that! :) However, I learned about ImageFont.truetype from the example. Unfortunately, I still can't get it to center on the screen. Here's what I distilled from the example and the text is no where near center:

from PIL import ImageFont
from papirus import PapirusTextPos
from datetime import datetime

Font = '/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf'
TheSize = 28

# Want today's date displayed, this stuff'll do it.
#  Example: Wed, Apr. 28 9:34AM
FMT = '%a, %b. %d %-I:%M %p'
DaDate = datetime.now().strftime(FMT)

DaLine = ImageFont.truetype(Font, TheSize)
line_width = DaLine.getmask(DaDate).getbbox()[2]
x = ((264-line_width) // 2)

print DaDate, x, line_width

text = PapirusTextPos(False)
text.AddText(DaDate, x, 35, fontPath=Font, Id="DaDate")
text.WriteAll()

I thought my screen size was 264x176 but using that width doesn't work. Width seems to depend on the font used and the text included. Help?

tvoverbeek commented 3 years ago

You have to take the screen width into account. The text is too wide when using size 28. You have to reduce the font size until it fits on the display. The width and height of the display are available. Here is my version:

#!/usr/bin/python3

from PIL import ImageFont
from papirus import PapirusTextPos
from datetime import datetime

Font = '/usr/share/fonts/truetype/freefont/FreeMonoBold.ttf'
TheSize = 28  # Initial size

text = PapirusTextPos(False)
# Get display size
disp_width  = text.papirus.width
disp_height = text.papirus.height
print('disp_width = ', disp_width, ' disp_height = ', disp_height)

# Want today's date displayed
# Example: Wed, Apr. 28 9:34AM
format = '%a, %b %d %-I:%M %p'
theDate = datetime.now().strftime(format)
print(theDate)

# Decrease font size until date fits on display
max_width = disp_width - 4  # Leave some margin
line_width = disp_width
TheSize += 1
while line_width > max_width:
   dateFont = ImageFont.truetype(Font, TheSize)
   bbox = dateFont.getmask(theDate).getbbox()
   print('bbox = ', bbox)
   line_width  = bbox[2] - bbox[0] 
   TheSize -= 1
line_height = bbox[3] - bbox[1]
print('line_width = ', line_width, ' line_height = ', line_height)

# Center date
x = (disp_width - line_width) // 2
y = (disp_height - line_height) // 2
print('x = ', x, ' y = ', y)

# Show it
text.AddText(theDate, x, y, size=TheSize, fontPath=Font, Id="theDate")
text.WriteAll()

Here the output for a 2.7" (264 x 176) and a picture:

pi@papirus-test:~ $ python3 txtpostest.py
disp_width =  264  disp_height =  176
Sat, May 01 8:38 PM
bbox =  (2, 0, 325, 25)
bbox =  (2, 0, 324, 24)
bbox =  (2, 0, 305, 23)
bbox =  (2, 0, 305, 22)
bbox =  (2, 0, 286, 21)
bbox =  (2, 0, 267, 20)
bbox =  (2, 0, 267, 19)
bbox =  (2, 0, 248, 18)
line_width =  246  line_height =  18
x =  9  y =  79
pi@papirus-test:~ $

20210501_204111

and for a 2.0" (200x96):

pi@papirus-test:~ $ python3 txtpostest.py
disp_width =  200  disp_height =  96
Sat, May 01 8:46 PM
bbox =  (2, 0, 325, 25)
bbox =  (2, 0, 324, 24)
bbox =  (2, 0, 305, 23)
bbox =  (2, 0, 305, 22)
bbox =  (2, 0, 286, 21)
bbox =  (2, 0, 267, 20)
bbox =  (2, 0, 267, 19)
bbox =  (2, 0, 248, 18)
bbox =  (2, 0, 248, 17)
bbox =  (2, 0, 229, 17)
bbox =  (2, 0, 210, 16)
bbox =  (2, 0, 210, 16)
bbox =  (2, 0, 191, 14)
line_width =  189  line_height =  14
x =  5  y =  41
pi@papirus-test:~

20210501_210321

ahnyerkeester commented 3 years ago

That was excellent. Thank you. I can't believe I blew it because of the size.

tvoverbeek commented 3 years ago

Closing the issue