How to load colorful emojis in pygame?

Question:

I want to use Pygame’s freetype module to load a colorful emoji via its unicode. Unfortunately I only get a monochrome image with the outline of the emoji:

Minimal, Reproducible Example:

import pygame
import pygame.freetype

pygame.init()
window = pygame.display.set_mode((200, 200))

seguisy80 = pygame.freetype.SysFont("segoeuisymbol", 100)
emoji, rect = seguisy80.render(' ', "black")
rect.center = window.get_rect().center

run = True
while run:  
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    window.fill("lightgray")
    window.blit(emoji, rect)
    pygame.display.flip()

pygame.quit()

How can I modify this code to get a full RGBA color image of an emoji?

Asked By: Rabbid76

||

Answers:

Unfortunately, colored font loading is not natively supported in Pygame. However, there is a workaround.
First you need a colored emoji font. For example, you can download one here: Apple Color Emoji for Linux.

Load this font using https://freetype.org/. Install freetype-py:

pip3 install freetype-py 

For Windows users, it should be mentioned that the installed package does not support the font and results in an "unimplemented feature" exception.
Download the package from Unofficial Windows Binaries for Python Extension Packages and install it. e.g.:

pip3 install freetype_py-2.2.0-cp310-cp310-win_amd64.whl

Now you’re prepared and can load an emoji from the font.Emojis and their Unicode can be found here: Emoticons (Unicode block).
Copy the emoji or use the unicode and load the glyph:

import freetype

face = freetype.Face("AppleColorEmoji.ttf")
face.set_char_size(int(face.available_sizes[-1].size)) 
    
face.load_char(' ', freetype.FT_LOAD_COLOR) # or face.load_char('U0001F603', freetype.FT_LOAD_COLOR)

The loaded glyph now needs to be turned into a pygame.Surface. To do this, use NumPy.
How this works in detail is explained in the answer to the question: How do I convert an OpenCV (cv2) image (BGR and BGRA) to a pygame.Surface object.

import numpy as np

ft_bitmap = face.glyph.bitmap
bitmap = np.array(ft_bitmap.buffer, dtype=np.uint8).reshape((ft_bitmap.rows, ft_bitmap.width, 4))
bitmap[:, :, [0, 2]] = bitmap[:, :, [2, 0]]
emoji = pygame.image.frombuffer(bitmap.flatten(), (ft_bitmap.width, ft_bitmap.rows), 'RGBA')

See also Text and font – Unicode


Minimal example:

import pygame
import freetype
import numpy as np

class Emojis:
    def __init__(self):
        self. face = freetype.Face("AppleColorEmoji.ttf")
        self.face.set_char_size(int(self.face.available_sizes[-1].size)) 
    def create_surface(self, unicode):
        self.face.load_char(unicode, freetype.FT_LOAD_COLOR)
        ft_bitmap = self.face.glyph.bitmap
        bitmap = np.array(ft_bitmap.buffer, dtype=np.uint8).reshape((ft_bitmap.rows, ft_bitmap.width, 4))
        bitmap[:, :, [0, 2]] = bitmap[:, :, [2, 0]]
        return pygame.image.frombuffer(bitmap.flatten(), (ft_bitmap.width, ft_bitmap.rows), 'RGBA')

pygame.init()
window = pygame.display.set_mode((200, 200))
emojis = Emojis()

emoji = emojis.create_surface(' ')
#emoji = emojis.create_surface('U0001F603')
rect = emoji.get_rect(center = window.get_rect().center)

run = True
while run:  
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    window.fill("lightgray")
    window.blit(emoji, rect)
    pygame.display.flip()

pygame.quit()
Answered By: Rabbid76

I just created
a small package
to make that easy.

You can just

pip install pygame-emojis

and then


from pygame_emojis import load_emoji

# Choose the size
size = (64, 64)

# Load the emoji as a pygame.Surface
surface = load_emoji(' ', size)

It download open source emojis as svg files.

Hope this helps.

Answered By: Oily