如何在Pygame中给字体描边

6

如何在字体上绘制轮廓线?
我想使用黑色字体,但背景必须是黑色的,所以很难看到字体。

我猜测myfont.render不支持在字体上绘制轮廓线。

还有其他方法吗?

3个回答

6

如果您是初学者,且不需要非常复杂的代码,并且只使用简单的字体(如arial,helvetica,calibri等)… 您只需在“角落”中4次以轮廓颜色绘制文本,然后将实际文本覆盖上去即可:

white = pygame.Color(255,255,255)
black = pygame.Color(0,0,0)

def draw_text(x, y, string, col, size, window):
    font = pygame.font.SysFont("Impact", size )
    text = font.render(string, True, col)
    textbox = text.get_rect()
    textbox.center = (x, y)
    window.blit(text, textbox)

x = 300
y = 300

# TEXT OUTLINE

# top left
draw_text(x + 2, y-2 , "Hello", black, 40, win)
# top right
draw_text(x +2, y-2 , "Hello", black, 40, win)
# btm left
draw_text(x -2, y +2 , "Hello", black, 40, win)
# btm right
draw_text(x-2, y +2 , "Hello", black, 40, win) 

# TEXT FILL

draw_text(x, y, "Hello", white, 40, win)

这更像是一种hack。就像你所说,对于简单的字体,它可能会正常工作,但你仍然会看到各个副本的角落。因此,尽管它的性质很简单,我不建议使用这种解决方案。 - mandulaj
1
我认为你不想这样放置“-”和“+”。这可能是复制粘贴错误,因为我们可以清楚地在注释(“左上”,“右上”,“左下”和“右下”)中看到你想要在文本的4个角落绘制边框���请再次阅读,你只在2个地方绘制了文本。一旦你进行编辑,这个答案就会生效。 - D_00

5

Pygame默认不支持这个功能,但一种方法是用轮廓颜色渲染文本并将其多次位移地贴到结果表面上,然后在其上方以所需颜色渲染文本。

pgzero使用了这种技术;下面展示了其简化版代码:

import pygame

_circle_cache = {}
def _circlepoints(r):
    r = int(round(r))
    if r in _circle_cache:
        return _circle_cache[r]
    x, y, e = r, 0, 1 - r
    _circle_cache[r] = points = []
    while x >= y:
        points.append((x, y))
        y += 1
        if e < 0:
            e += 2 * y - 1
        else:
            x -= 1
            e += 2 * (y - x) - 1
    points += [(y, x) for x, y in points if x > y]
    points += [(-x, y) for x, y in points if x]
    points += [(x, -y) for x, y in points if y]
    points.sort()
    return points

def render(text, font, gfcolor=pygame.Color('dodgerblue'), ocolor=(255, 255, 255), opx=2):
    textsurface = font.render(text, True, gfcolor).convert_alpha()
    w = textsurface.get_width() + 2 * opx
    h = font.get_height()

    osurf = pygame.Surface((w, h + 2 * opx)).convert_alpha()
    osurf.fill((0, 0, 0, 0))

    surf = osurf.copy()

    osurf.blit(font.render(text, True, ocolor).convert_alpha(), (0, 0))

    for dx, dy in _circlepoints(opx):
        surf.blit(osurf, (dx + opx, dy + opx))

    surf.blit(textsurface, (opx, opx))
    return surf

def main():
    pygame.init()

    font = pygame.font.SysFont(None, 64)

    screen = pygame.display.set_mode((350, 100))
    clock = pygame.time.Clock()

    while True:
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return
        screen.fill((30, 30, 30))

        screen.blit(render('Hello World', font), (20, 20))

        pygame.display.update()
        clock.tick(60)

if __name__ == '__main__':
    main()

enter image description here


我不知道这是怎么工作的,因为我是个初学者,但它完美地运行了!就像我想要的一样。然而,信件的下部看起来有点被切了。不多,只是一点点。可能是我的字体的问题,但通常渲染时并不是这样的。你知道为什么会发生这种情况吗? - jwoojin9
你使用哪种字体? - sloth
好的,这是我的字体问题。现在我正在使用另一种字体,所以没问题了。 - jwoojin9

0

您可以使用遮罩为文本添加轮廓。以下是一个示例:

import pygame

def add_outline_to_image(image: pygame.Surface, thickness: int, color: tuple, color_key: tuple = (255, 0, 255)) -> pygame.Surface:
    mask = pygame.mask.from_surface(image)
    mask_surf = mask.to_surface(setcolor=color)
    mask_surf.set_colorkey((0, 0, 0))

    new_img = pygame.Surface((image.get_width() + 2, image.get_height() + 2))
    new_img.fill(color_key)
    new_img.set_colorkey(color_key)

    for i in -thickness, thickness:
        new_img.blit(mask_surf, (i + thickness, thickness))
        new_img.blit(mask_surf, (thickness, i + thickness))
    new_img.blit(image, (thickness, thickness))

    return new_img

以下是我如何使用此函数创建带有2像素黑色轮廓的白色文本:

text_surf = myfont.render("test", False, (255, 255, 255)).convert()
text_with_ouline = add_outline_to_image(text_surf, 2, (0, 0, 0))

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接