Support setting a default font
What did you do?
Was printing CJK characters to an image but got an AttributeError. No doubt the default font wasn't supporting such characters.
What did you expect to happen?
Understand I can use Unicode-friendly fonts everytime I do text(). However, can I somehow change the default font so that I won't need to change everywhere in my program text() with a font?
What actually happened?
Checking the docs there's PIL.ImageFont.load_default() to
Load a “better than nothing” default font. Well, it is very clear. But can I provide some "better than nothing" default for my own use?
What are your OS, Python and Pillow versions?
- OS: Ubuntu
- Python: 3.8.13
- Pillow: 9.2.0
from PIL import Image, ImageDraw
im = Image.new("RGB", (400, 300))
draw = ImageDraw.Draw(im)
draw.text((10, 10), "你好")
im.show()
It gives:
AttributeError: 'ImageFont' object has no attribute 'getmask2'
If you're looking for an immediate solution, you could patch Pillow. Using one of our test fonts,
from PIL import ImageFont
ImageFont.load_default = lambda: ImageFont.truetype("Tests/fonts/NotoSansJP-Regular.otf")
In context,
from PIL import Image, ImageDraw, ImageFont
ImageFont.load_default = lambda: ImageFont.truetype("Tests/fonts/NotoSansJP-Regular.otf")
im = Image.new("RGB", (400, 300))
draw = ImageDraw.Draw(im)
draw.text((10, 10), "你好")
im.show()
Awesome! I am practicing an identical workaround.
However, patching load_default to set default isn't something we want to write in the documentation.
Looking forward to a consistent and reliable interface to handle this.
What do you think of this interface for setting a default font?
from PIL import ImageDraw, ImageFont
ImageDraw.ImageDraw.font = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 120)
I've created PR #6484 with this change.
Looks good, but why does it go under ImageDraw rather than ImageFont?
Is ImageFont.load_default used somewhere else where we want flexibility over consistency?
You can already set the default font on a per-ImageDraw instance basis, e.g.
from PIL import Image, ImageDraw, ImageFont
im = Image.new("RGB", (400, 300))
draw = ImageDraw.Draw(im)
draw.font = ImageFont.truetype("Tests/fonts/NotoSansJP-Regular.otf")
draw.text((10, 10), "你好")
im.show()
This is currently undocumented, but I wouldn't expect it to be removed without a deprecation notice. Perhaps just documenting this field would be good enough for you?
@radarhere's PR adds the option to set a default value globally for all ImageDraw instances without an explicit font set.
ImageFont.load_default isn't used anywhere else (except for a small number of tests), but despite being a function, it can be treated sort of like a getter for a constant. The function contains a base64 encoded font file that it simply loads and returns every time you call it. I would therefore find it strange to change its behaviour by adding a set_default function.
Yeah, the constant constraint makes sense to me.