SVG rendering in a PyGame application

前端 未结 9 1121
悲哀的现实
悲哀的现实 2020-12-02 12:34

In a pyGame application, I would like to render resolution-free GUI widgets described in SVG.

What tool and/or library can I use to reach this goal ?

(I like

相关标签:
9条回答
  • 2020-12-02 12:59

    You can use Cairo (with PyCairo), which has support for rendering SVGs. The PyGame webpage has a HOWTO for rendering into a buffer with a Cairo, and using that buffer directly with PyGame.

    0 讨论(0)
  • 2020-12-02 13:01

    This is a complete example which combines hints by other people here. It should render a file called test.svg from the current directory. It was tested on Ubuntu 10.10, python-cairo 1.8.8, python-pygame 1.9.1, python-rsvg 2.30.0.

    #!/usr/bin/python
    
    import array
    import math
    
    import cairo
    import pygame
    import rsvg
    
    WIDTH = 512
    HEIGHT = 512
    
    data = array.array('c', chr(0) * WIDTH * HEIGHT * 4)
    surface = cairo.ImageSurface.create_for_data(
        data, cairo.FORMAT_ARGB32, WIDTH, HEIGHT, WIDTH * 4)
    
    pygame.init()
    window = pygame.display.set_mode((WIDTH, HEIGHT))
    svg = rsvg.Handle(file="test.svg")
    ctx = cairo.Context(surface)
    svg.render_cairo(ctx)
    
    screen = pygame.display.get_surface()
    image = pygame.image.frombuffer(data.tostring(), (WIDTH, HEIGHT),"ARGB")
    screen.blit(image, (0, 0)) 
    pygame.display.flip() 
    
    clock = pygame.time.Clock()
    while True:
        clock.tick(15)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                raise SystemExit
    
    0 讨论(0)
  • 2020-12-02 13:03

    Cairo cannot render SVG out of the box. It seems we have to use librsvg.

    Just found those two pages:

    • Rendering SVG with libRSVG,Python and c-types
    • How to use librsvg from Python

    Something like this should probably work (render test.svg to test.png):

    import cairo
    import rsvg
    
    WIDTH, HEIGHT  = 256, 256
    surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, WIDTH, HEIGHT)
    
    ctx = cairo.Context (surface)
    
    svg = rsvg.Handle(file="test.svg")
    svg.render_cairo(ctx)
    
    surface.write_to_png("test.png")
    
    0 讨论(0)
  • 2020-12-02 13:05

    pynanosvg can be used to load and rasterize Vector Graphics (SVG) files. Install Cython and pynanosvg:

    pip install Cython
    pip install pynanosvg
    

    The SVG file can be read, rasterized and loaded into a pygame.Surface object with the following function:

    def load_svg(filename, scale=None, size=None, clip_from=None, fit_to=None, foramt='RGBA'):
        svg = Parser.parse_file(filename)
        scale = min((fit_to[0] / svg.width, fit_to[1] / svg.height)
                    if fit_to else ([scale if scale else 1] * 2))
        width, height = size if size else (svg.width, svg.height)
        surf_size = round(width * scale), round(height * scale)
        buffer = Rasterizer().rasterize(svg, *surf_size, scale, *(clip_from if clip_from else 0, 0))
        return  pygame.image.frombuffer(buffer, surf_size, foramt)
    

    See also svgsurf.py


    Minimal example:

    import pygame
    from svg import Parser, Rasterizer
    
    def load_svg(filename, scale=None, size=None, clip_from=None, fit_to=None, foramt='RGBA'):
        svg = Parser.parse_file(filename)
        scale = min((fit_to[0] / svg.width, fit_to[1] / svg.height)
                    if fit_to else ([scale if scale else 1] * 2))
        width, height = size if size else (svg.width, svg.height)
        surf_size = round(width * scale), round(height * scale)
        buffer = Rasterizer().rasterize(svg, *surf_size, scale, *(clip_from if clip_from else 0, 0))
        return  pygame.image.frombuffer(buffer, surf_size, foramt)
    
    pygame.init()
    window = pygame.display.set_mode((300, 300))
    clock = pygame.time.Clock()
    
    pygameSurface = load_svg('Ice.svg', fit_to = (window.get_width()*3//4, window.get_height()))
    
    run = True
    while run:
        clock.tick(60)
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
    
        window.fill((127, 127, 127))
        window.blit(pygameSurface, pygameSurface.get_rect(center = window.get_rect().center))
        pygame.display.flip()
    
    pygame.quit()
    exit()
    
    0 讨论(0)
  • 2020-12-02 13:08

    I realise this doesn't exactly answer your question, but there's a library called Squirtle that will render SVG files using either Pyglet or PyOpenGL.

    0 讨论(0)
  • 2020-12-02 13:10

    Based on other answers, here's a function to read a SVG file into a pygame image - including correcting color channel order and scaling:

    def pygame_svg( svg_file, scale=1 ):
        svg = rsvg.Handle(file=svg_file)
        width, height= map(svg.get_property, ("width", "height"))
        width*=scale; height*=scale
        data = array.array('c', chr(0) * width * height * 4)
        surface = cairo.ImageSurface.create_for_data( data, cairo.FORMAT_ARGB32, width, height, width*4)
        ctx = cairo.Context(surface)
        ctx.scale(scale, scale)
        svg.render_cairo(ctx)
    
        #seemingly, cairo and pygame expect channels in a different order...
        #if colors/alpha are funny, mess with the next lines
        import numpy
        data= numpy.fromstring(data, dtype='uint8')
        data.shape= (height, width, 4)
        c= data.copy()
        data[::,::,0]=c[::,::,1]
        data[::,::,1]=c[::,::,0]
        data[::,::,2]=c[::,::,3]
        data[::,::,3]=c[::,::,2]
    
        image = pygame.image.frombuffer(data.tostring(), (width, height),"ARGB")
        return image
    
    0 讨论(0)
提交回复
热议问题