如何在 pygame 中加载彩色表情符号?

How to load colorful emojis in pygame?

我想使用 Pygame 的 freetype 模块通过其 unicode 加载彩色表情符号。不幸的是,我只得到一张带有表情符号轮廓的单色图像:

最小的、可重现的例子:

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()

如何修改此代码以获得表情符号的完整 RGBA 彩色图像?

遗憾的是,彩色字体加载在 Pygame 中不受原生支持。但是,有一个解决方法。 首先你需要一个彩色的表情符号字体。例如,您可以在此处下载一个:Apple Color Emoji for Linux.

使用 https://freetype.org/. Install freetype-py 加载此字体:

pip3 install freetype-py 

对于Windows用户,需要注意的是安装包不支持该字体,导致出现“未实现的功能”异常。 从 Unofficial Windows Binaries for Python Extension Packages 下载软件包并安装。例如:

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

现在您已准备就绪,可以从 font.Emojis 加载表情符号,可以在此处找到它们的 Unicode:Emoticons (Unicode block)。 复制表情符号或使用 unicode 并加载字形:

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)

加载的字形现在需要变成 pygame.Surface. To do this, use NumPy。 问题的答案中详细解释了这是如何工作的:.

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')

另见 Text and font - Unicode


最小示例:

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()