· 2 min read
Generating Font Previews with Python and Pillow for Enhanced UX
Using Python and Pillow, I've automated the creation of font previews to simplify selection.

Selecting fonts from lists is tedious when users can’t visualize how text will look. I wrote a Python script using Pillow to auto-generate font previews for easier selection.
In this post, I’ll explain my frustrating experience, the Python automation solution, results, and lessons learned.
The Problematic Font Selection Process
While building a social media post creator web app (Postnitro.ai), I included customizable fonts. Users could choose from 50+ font options.
However, the interface only displayed names in plain text. Users had to:
- Pick a font
- Apply to their text
- Check how it looked
- Repeat until satisfied
This frustrating trial-and-error process meant guessing how fonts would appear. Users wasted time visualization was impossible.
I needed to show previews of each font alongside names, so users could see how text would render before selecting.
Automating Previews with Python and Pillow
To solve this, I wrote a Python script using Pillow that loops through available fonts and creates and save the preview images for me.
The script:
- Downloads font files from a JSON list of Google Fonts URLs
- Checks for errors downloading each font
- Uses Pillow to create a simple white background image
- Draws the font name on the image in black text
- Saves the preview as a PNG file
This allowed me to automatically generate a preview image for every font without tedious manual work.
Here is the json file structure:
[
{
"family":"Gaegu",
"full_name":"Gaegu Light",
"postscript_name":"Gaegu-Light",
"style":"Gaegu-Light",
"url":"https://fonts.gstatic.com/s/gaegu/v10/TuGSUVB6Up9NU57nifw74sdtBk0x.ttf",
"category":"handwriting"
},
{
"family":"Gaegu",
"full_name":"Gaegu Bold",
"postscript_name":"Gaegu-Bold",
"style":"Gaegu-Bold",
"url":"https://fonts.gstatic.com/s/gaegu/v10/TuGSUVB6Up9NU573jvw74sdtBk0x.ttf",
"category":"handwriting"
},
{
"family":"Gaegu",
"full_name":"Gaegu Regular",
"postscript_name":"Gaegu-Regular",
"style":"Gaegu-Regular",
"url":"https://fonts.gstatic.com/s/gaegu/v10/TuGfUVB6Up9NU6ZLodgzydtk.ttf",
"category":"handwriting"
},
{
"family":"Open Sans",
"full_name":"Open Sans Light",
"postscript_name":"OpenSans-Light",
"style":"OpenSans-Light",
"url":"https://fonts.gstatic.com/s/opensans/v27/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsiH0C4nY1M2xLER.ttf",
"category":"sans-serif"
}
// More google fonts here...
]
Here is the full script:
# we're importing the needed libraries | |
import json | |
import requests | |
from PIL import Image, ImageDraw, ImageFont | |
from io import BytesIO | |
import os | |
# open fonts.json file to load fonts | |
with open('fonts.json') as f: | |
fonts = json.load(f) | |
# set directory for font previews | |
outdir = './font_previews' | |
# creates previews directory if it doesn't exist | |
os.makedirs(outdir, exist_ok=True) | |
# for each font in the fonts list, it will attempt the following: | |
for idx, font in enumerate(fonts): | |
try: | |
# downloads the font file from the URL provided in the font list | |
response = requests.get(font['url']) | |
# create a bytesIO object with downloaded font. This object behaves like a file object. | |
font_file = BytesIO(response.content) | |
# if the response from the server is not successful (status code 200), | |
# it will print a message and will skip the rest of the loop for the current font | |
if response.status_code != 200: | |
print(f"Skipping font {font['postscript_name']} due to unsuccessful download from {font['url']}.") | |
continue | |
# creates a new image with white background | |
img = Image.new('RGB', (500, 200), color='white') | |
# we can now do drawing operations on this opened image | |
draw = ImageDraw.Draw(img) | |
# loads the downloaded font file to be later used on the image | |
loadfont = ImageFont.truetype(font_file, 36) | |
# calculates size in pixels of the font family string | |
left, upper, right, lower = draw.textbbox((0, 0), font['family'], font=loadfont) | |
w, h = right - left, lower - upper | |
# calculates the center position in the image for our string to be placed | |
text_pos = ((img.width - w) / 2, (img.height - h) / 2) | |
# places the text (the font family string) at the calculated position | |
draw.text(text_pos, font['family'], fill='black', font=loadfont) | |
# sets the output filename | |
outfile = os.path.join(outdir, font['postscript_name'] + '.png') | |
# and saves the image in a PNG format | |
img.save(outfile) | |
# notifies by printing | |
print(f"Saved {outfile}") | |
except Exception as e: | |
# handles exceptions during font handling, notifies about the error. | |
print(f"An error occurred with font {font['postscript_name']}: {e}") |
This script enabled generating a set of preview images that could be displayed in the font selection interface.
Integrating Previews to Improve UX
With the script generating previews, I could display them in the font selection interface alongside names:
Now users could visualize how text would look in any font before picking one.
This eliminated the frustrating guessing game and improved the overall experience.
Lessons Learned Automating with Python
This project taught me:
- Python automation simplifies repetitive digital asset creation.
- Pillow provides an easy way to dynamically draw and save images.
- For better UX, preview images should accompany font lists.
- Automated solutions save time compared to manual repetition.
- Scripts allow instantly updating assets like previews.
Summary
- Font picking is frustrating when users can’t visualize options.
- Manually creating previews is time-consuming.
- Python automation generatively handles preview generation.
- Pillow draws and saves font previews on the fly.
- Previews alongside fonts improves selection UX.
- python
- pillow
- python-automation
- font-previews
- font-selection
- fonts
- preview-generation
- automation
- python-scripting
- python-for-design
- automate-with-python
- improving-ux
- user-experience
- web-development
- programming

Subscribe to my newsletter to get the latest updates on my blog.