在 Python Pygame 上显示 SVG(来自字符串)

Raj*_*roi 5 python svg pygame python-3.x pygame-surface

我有一个以字符串表示的 SVG 图形

svg_string='<svg height="100" width="500"><ellipse cx="240" cy="50" rx="220" ry="30" style="fill:yellow" /><ellipse cx="220" cy="50" rx="190" ry="20" style="fill:white" /></svg>'
Run Code Online (Sandbox Code Playgroud)

我想在Python启动的窗口上显示由 表示的图形svg_string,它是2个椭圆。

其伪代码应该是这样的

import pygame


def display_svg_figure(screen, svg_string):
    #   Code that draws the rendered SVG string on
    #   the screen
    pass

background_colour = (255, 255, 255)
(width, height) = (900, 900)

screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Display SVG')
screen.fill(background_colour)

pygame.display.flip()

svg_string='<svg height="100" width="500"><ellipse cx="240" cy="50" rx="220" ry="30" style="fill:yellow" /><ellipse cx="220" cy="50" rx="190" ry="20" style="fill:white" /></svg>'
display_svg_figure(screen, svg_string)


running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
Run Code Online (Sandbox Code Playgroud)

我基本上正在研究该方法的实现display_svg_figure(screen,svg_string)

我也愿意使用非 pygame 库,只要它遵循以下简单接口并且可以将其包含在 pygame 中

from SOME_LIBRARY import SOME_COMPONENT

svg_string="......"
SOME_COMPONENT.display(svg_string)
Run Code Online (Sandbox Code Playgroud)

我已经看过了pynanosvg,但它不再受支持并且失败了,所以不能满足我的需要。

Display SVG file in Python中给出的解决方案似乎不符合要求,因为它在 PyGame 中不起作用。如果有人可以让它工作,请告诉我。

Rab*_*d76 7

如何读取可扩展矢量图形 (SVG)文件在 PyGame 应用程序中的 SVG 渲染中得到解答。


Pygame 版本 2.0 支持 SVG 文件。从版本 2.0.2 开始,SDL Image 支持 SVG(可缩放矢量图形)文件(请参阅SDL_image 2.0)。因此,在 pygame 版本 2.0.1 中,可以使用流 ( )将 SVG 文件加载到pygame.Surface对象 中:pygame.image.load()io.BytesIO

svg_string = '<svg height="100" width="500"><ellipse cx="240" cy="50" rx="220" ry="30" style="fill:yellow" /><ellipse cx="220" cy="50" rx="190" ry="20" style="fill:white" /></svg>'
pygame_surface = pygame.image.load(io.BytesIO(svg_string.encode()))
Run Code Online (Sandbox Code Playgroud)

最小的例子:

import pygame
import io

pygame.init()
window = pygame.display.set_mode((500, 200))
clock = pygame.time.Clock()

svg_string = '<svg height="100" width="500"><ellipse cx="240" cy="50" rx="220" ry="30" style="fill:yellow" /><ellipse cx="220" cy="50" rx="190" ry="20" style="fill:white" /></svg>'
pygame_surface = pygame.image.load(io.BytesIO(svg_string.encode()))

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

    window.fill((255, 255, 255))
    window.blit(pygame_surface, pygame_surface.get_rect(center = window.get_rect().center))
    pygame.display.flip()

pygame.quit()
exit()
Run Code Online (Sandbox Code Playgroud)

在 Pygame 2 之前,您必须使用其他库来实现可扩展矢量图形加载。渲染 SVG 字符串有多种可能性。

一个简单的可能性是使用svglib。安装svglib

pip install svglib
Run Code Online (Sandbox Code Playgroud)

编写一个函数来解析和光栅化 SVG 字符串并创建一个pygame.Surface对象:

from svglib.svglib import svg2rlg
import io

def load_svg(svg_string):
    svg_io = io.StringIO(svg_string)
    drawing = svg2rlg(svg_io)
    str = drawing.asString("png")
    byte_io = io.BytesIO(str)
    return pygame.image.load(byte_io)
Run Code Online (Sandbox Code Playgroud)

但是,透明背景似乎存在问题。有一个关于此主题的问题如何使 png 背景透明?第171

另一种解决方案(显然速度较慢)是使用 CairoSVG。使用该功能cairosvg.svg2png矢量图形(SVG)文件可以直接转换为[便携式网络图形(PNG)]文件

安装CairoSVG

pip install CairoSVG
Run Code Online (Sandbox Code Playgroud)

编写一个将 SVF 文件转换为 PNG ( ByteIO) 并创建pygame.Surface对象的函数,可能如下所示:

import cairosvg
import io

def load_svg(filename):
    new_bites = cairosvg.svg2png(url = filename)
    byte_io = io.BytesIO(new_bites)
    return pygame.image.load(byte_io)
Run Code Online (Sandbox Code Playgroud)

另请参见svgsurf.py


最小的例子:

from svglib.svglib import svg2rlg
import pygame
import io

def load_svg_svglib(svg_string):
    svg_io = io.StringIO(svg_string)
    drawing = svg2rlg(svg_io)
    str = drawing.asString("png")
    byte_io = io.BytesIO(str)
    svg_surf = pygame.image.load(byte_io)
    return svg_surf

def display_svg_figure(screen, svg_string):
    surf = load_svg_svglib(svg_string)
    screen.blit(surf, (0, 0))

background_colour = (255, 255, 255)
(width, height) = (900, 900)

screen = pygame.display.set_mode((width, height))
pygame.display.set_caption('Display SVG')
screen.fill(background_colour)

svg_string='<svg height="100" width="500"><ellipse cx="240" cy="50" rx="220" ry="30" style="fill:yellow" /><ellipse cx="220" cy="50" rx="190" ry="20" style="fill:white" /></svg>'
display_svg_figure(screen, svg_string)

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

    pygame.display.flip()
Run Code Online (Sandbox Code Playgroud)