Rendu SVG dans une application PyGame
Dans une applicationpyGame , je voudrais rendre les widgets GUI sans résolution décrits en SVG.
Quel outil et/ou bibliothèque puis-je utiliser pour atteindre cet objectif ?
(j'aime la boîte à outils OCEMP GUI mais elle semble dépendre du bitmap pour son rendu)
8 réponses
Ceci est un exemple complet qui combine des conseils d'autres personnes ici. Il devrait rendre un fichier appelé test.svg à partir du répertoire courant. Il a été testé sur 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
Vous pouvez utiliser Cairo (avec PyCairo), qui prend en charge le rendu des SVG. La page Web PyGame a un HOWTO pour le rendu dans un tampon avec un Cairo, et l'utilisation de ce tampon directement avec PyGame.
Je me rends compte que cela ne répond pas exactement à votre question, mais il y a une bibliothèque appelée Squirtle qui rendra les fichiers SVG en utilisant Pyglet ou PyOpenGL.
Pygamesvg semble faire ce que vous voulez (bien que je n'ai pas essayé).
Cairo ne peut pas rendre SVG hors de la boîte. Il semble que nous devons utiliser librsvg.
Vient de trouver ces deux pages:
Quelque chose comme ça devrait probablement fonctionner (render test.svg à 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")
Le dernier commentaire s'est écrasé quand je l'ai couru parce que svg.render_cairo () attend un contexte cairo et non une surface cairo. J'ai créé et testé la fonction suivante et elle semble fonctionner correctement sur mon système.
import array,cairo, pygame,rsvg
def loadsvg(filename,surface,position):
WIDTH = surface.get_width()
HEIGHT = surface.get_height()
data = array.array('c', chr(0) * WIDTH * HEIGHT * 4)
cairosurface = cairo.ImageSurface.create_for_data(data, cairo.FORMAT_ARGB32, WIDTH, HEIGHT, WIDTH * 4)
svg = rsvg.Handle(filename)
svg.render_cairo(cairo.Context(cairosurface))
image = pygame.image.frombuffer(data.tostring(), (WIDTH, HEIGHT),"ARGB")
surface.blit(image, position)
WIDTH = 800
HEIGHT = 600
pygame.init()
window = pygame.display.set_mode((WIDTH, HEIGHT))
screen = pygame.display.get_surface()
loadsvg("test.svg",screen,(0,0))
pygame.display.flip()
clock = pygame.time.Clock()
while True:
clock.tick(15)
event = pygame.event.get()
for e in event:
if e.type == 12:
raise SystemExit
La question est assez ancienne mais 10 ans ont passé et il y a une nouvelle possibilité qui fonctionne et ne nécessite plus librsvg
. Il y a Cython wrapper sur la bibliothèque nanosvg et cela fonctionne:
from svg import Parser, Rasterizer
def load_svg(filename, surface, position, size=None):
if size is None:
w = surface.get_width()
h = surface.get_height()
else:
w, h = size
svg = Parser.parse_file(filename)
rast = Rasterizer()
buff = rast.rasterize(svg, w, h)
image = pygame.image.frombuffer(buff, (w, h), 'ARGB')
surface.blit(image, position)
J'ai trouvé la solution Cairo/rsvg trop compliquée pour se mettre au travail car les dépendances sont assez obscures à installer.
Basé sur d'autres réponses, voici une fonction pour lire un fichier SVG dans une image pygame - y compris la correction de l'ordre des canaux de couleur et la mise à l'échelle:
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