DEV Community

Cover image for How to Render Emojis and International Text on Images with Python
Franco Zanardi
Franco Zanardi

Posted on

How to Render Emojis and International Text on Images with Python

If you've ever generated images with text in Python, you've likely seen this frustrating sight: □□□. These empty boxes, known as "tofu," appear when your chosen font doesn't have a glyph for a specific character, a common problem with emojis (), symbols (), and non-Latin scripts (世界).

While standard libraries often require complex manual workarounds, this tutorial will show you how the Python library pictex solves this problem automatically.

Setup

First, let's get pictex installed. All you need is pip:

pip install pictex
Enter fullscreen mode Exit fullscreen mode

Now, let's get straight to the solution.

The "It Just Works" Solution: Automatic System Fallback

Let's attempt to render a string containing English, Japanese, and an emoji using a standard font like "Georgia", which does not support all these characters. With pictex, you don't need any special configuration.

from pictex import Canvas

canvas = (
    Canvas()
    .font_family("Georgia") # A beautiful but still limited serif font
    .font_size(80)
    .color("darkslateblue")
    .padding(20)
    .background_color("whitesmoke")
)

text_with_mixed_chars = "Hello, 世界 ✨"
image = canvas.render(text_with_mixed_chars)
image.save("font_autofallback.png")
Enter fullscreen mode Exit fullscreen mode

The result is a perfectly rendered image, with no "tofu":

An image showing 'Hello, 世界 ✨' rendered perfectly with mixed fonts

How It Works

Notice we didn't do anything special. pictex handles this out of the box because of its automatic font fallback system.

Here’s the mechanism: When pictex prepares to render text, it checks if the primary font (in this case, "Georgia") supports each character. If it finds a character that the font doesn't have a glyph for, it automatically searches your operating system for an installed font that can render it. It then seamlessly uses that fallback font for only the missing characters.

Full Control with .font_fallbacks()

Automatic fallback is fantastic, but sometimes you need more control. You might want to ensure a specific stylistic consistency for certain languages or use a custom emoji font you provide.

This is where the .font_fallbacks() method comes in. It lets you provide a list of your own font files to try before pictex resorts to searching the entire system.

The full fallback chain is executed in this order:

  1. Primary Font: The font set with .font_family().
  2. User-Defined Fallbacks: The list of fonts provided to .font_fallbacks(), in the order you list them.
  3. Automatic System Search: If no font in the above steps can render the character, pictex performs its default mechanism of searching for any suitable font on the system.

Let's use this to specify a particular font for the Japanese text. We'll use the free "Noto Sans JP" font from Google Fonts.

from pictex import Canvas

# A stylish primary font (doesn't support Japanese or emojis)
primary_font = "Lato-BoldItalic.ttf" 

# A specific Japanese font we want to use as a fallback
japanese_font = "NotoSansJP-Regular.ttf"

canvas = (
    Canvas()
    .font_family(primary_font)
    # Tell PicTex to try our Japanese font before searching the system
    .font_fallbacks(japanese_font)
    .font_size(80)
    .color("olive")
    .padding(20)
    .background_color("whitesmoke")
)

text_with_mixed_chars = "Hello, 世界 ✨"
image = canvas.render(text_with_mixed_chars)
image.save("font_custom_fallback.png")
Enter fullscreen mode Exit fullscreen mode

In this result, "Hello," is rendered with our primary Lato font, "世界" is rendered with Noto Sans JP (our specific choice), and "✨" is rendered using an emoji font found automatically on the system. We have achieved perfect rendering with full artistic control.

An image showing perfect rendering using a user-defined fallback font

Conclusion

Handling complex, multi-lingual text and emojis is a notoriously difficult part of programmatic image generation. With pictex, this problem is solved from the ground up.

  • For most cases, the automatic system fallback works flawlessly and requires no extra code.
  • For full creative control, the .font_fallbacks() method gives you the power to define your own priority list of fonts, ensuring stylistic consistency across different character sets.

Stop fighting with tofu and start creating beautiful, reliable text visuals today.

If you found this tutorial helpful, I encourage you to explore the GitHub Repository.

Happy coding

Top comments (0)