[Rod Stephens Books]
Index Books Python Examples About Rod Contact
[Mastodon] [Bluesky]
[Build Your Own Ray Tracer With Python]

[Beginning Database Design Solutions, Second Edition]

[Beginning Software Engineering, Second Edition]

[Essential Algorithms, Second Edition]

[The Modern C# Challenge]

[WPF 3d, Three-Dimensional Graphics with WPF and C#]

[The C# Helper Top 100]

[Interview Puzzles Dissected]

Title: Draw text with PIL in Python

[Text drawn with PIL in Python]

The general approach is fairly easy. You just load the font that you want to use and then call the ImageDraw object's text method to draw the text. Unfortunately, there are a few details that make this harder than it should be.

  • PIL doesn't have a good way to find the font you want. It would be nice to give the font's name as in "Times New Roman" or "Arial Bold Italic." Sadly you need to specify the font's file name instead.
  • It's not obvious how to figure out what fonts you have installed on your system or what their file names are. To make this harder, I'm sure this differs by operating system.
  • PIL also doesn't recover gracefully (for example, by finding a similar font) if you try to use a font file that isn't present. It just throws its hands up in despair and says OSError: cannot open resource. (You could probably use os.path.isfile to verify that the font file exists before you try to use it, but I'm going to be lazy and skip that.)
I'll explain how I did this for this example in Windows. You'll have to make adjustments if you're using some other operating system.

Finding Fonts

In Windows, use File Explorer (or whatever Microsoft is calling it this week) to open the C:\Windows\Fonts folder. Unfortunately, this is a special folder and File Explorer handles it in a weird way. Rather than listing files and subfolders, Explorer displays samples of the fonts.

A font can either be a single file (it looks like a document showing a sample of the font) or a subfolder containing multiple font files (it looks like a stack of documents). Subfolders contain font families like Calibri, Calibri Bold, Calibri Bold Italic, and so forth. (File Explorer's Details view makes it a bit easier to see which variations the fonts have like Bold or Bold Italic.)

If you double-click on a single file, you'll see samples of the font.

If you double-click on a subfolder, you'll see individual documents showing samples of the fonts.

Another weird thing about the way File Explorer displays this folder is that you cannot search it in quite the same way you can search normal folders. You can search for a strings that occur in font names like "Times," "Italic," or "Gothic." Sadly, you cannot search for file name extensions like "otf" (for OpenType font) or "ttf" (for TrueType font).

[In Windows, the Properties dialog shows a font's file name] After you find an individual font file that you like (not a folder), right-click on it and select Properties. The font's file name is shown in the text box at the top of the Properties dialog as shown in the picture on the right. That's the name you need to use in your Python code.

Example Code

The following code shows how the example program draws its text.

# Drawing parameters. wid = 300 hgt = 300 margin = 10 # Create the PIL image. image = Image.new('RGB', (wid, hgt), (255, 255, 255)) # Create a Draw object to draw on the image. dr = ImageDraw.Draw(image) # Draw some text. font = ImageFont.truetype('arial.ttf', 80) dr.text((60, 20), 'Arial', font=font, fill='red') font = ImageFont.truetype('timesbi.ttf', 30) dr.text((10, 70), 'Times\nNew\nRoman\nBold\nItalic', font=font, fill='green') font = ImageFont.truetype('GARA.TTF', 45) dr.text((80, 140), 'Garamond', font=font, fill='blue') font = ImageFont.truetype('courbd.ttf', 27) dr.text((5, 210), 'Courier New Bold', font=font, fill='orange') # Convert the image into a PhotoImage for tkinter to display. self.photo_image = ImageTk.PhotoImage(image) # Display the image. canvas = tk.Canvas(self.window, bg='white', width=wid, height=hgt, borderwidth=0, highlightthickness=0) canvas.pack(side=tk.LEFT, anchor=tk.NW, padx=margin, pady=margin) canvas.create_image(0, 0, image=self.photo_image, anchor=tk.NW)

This code defines some drawing parameters, creates a PIL Image, and makes an associated Draw object to draw on it.

Next, the program uses ImageFont.truetype to create a font. Windows supports both TrueType and OpenType fonts. OpenType fonts are newer, but they're not installed in Windows by default so I'm using TrueType fonts. Of course, the fonts available on your system may differ.

The code then calls the dr object's text method to draw some sample text passing that method the coordinates where the text should go, the string to draw, the font, and the desired color.

The program repeats those steps a few more times to draw more samples.

There are a few things to notice about this code.

  • If you include newlines in the text as in Times\nNew\nRoman\nBold\nItalic, the result is drawn across multiple lines.
  • Like all objects drawn in PIL, Text can overlap with other objects. If you don't want things to overlap, you need to position things appropriately.
  • PIL draws the text with antialiasing so the result appears smooth. (For more on antialiasing in PIL, see my post Provide antialiasing with PIL and Python.)
  • Fonts are powerful things and many text-drawing tools can modify them by doing such things as stretching or skewing the fonts. PIL doesn't do that and just draws the basic font provided by the font file. (At least we have anti-aliasing.)
Next, the example converts the PIL image into a PhotoImage that tkinter can understand. As is always the case when displaying PIL images in tkinter, the PhotoImage must be saved in a non-volatile way so tkinter can redisplay it when needed. If you save it in a local variable, it will be garbage collected and tkinter won't display it.

The example finishes by displaying the PIL image in a Canvas widget.

Conclusion

The basic idea is simple: load the font and draw the text. The hardest part is finding the font file that you want to use.

If you want to run your program on other computers, you'll need to ensure that the font is available on that computer, too. You can make that more likely by sticking with the most commonly used fonts. Here's a list of some that you might use.

  1. Helvetica
  2. Arial
  3. Calibri
  4. Times New Roman
  5. Garamond
  6. Calibri
  7. Verdana
  8. Century Gothic
  9. Comic Sans
  10. Courier New
This list includes some of the more popular fonts plus Courier New, which is useful because it's monospaced and therefore useful for displaying code.

Download the example to see additional details.

© 2024 Rocky Mountain Computer Consulting, Inc. All rights reserved.