python PyGame 应用程序中的 SVG 渲染
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/120584/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
SVG rendering in a PyGame application
提问by Pierre-Jean Coudert
In a pyGameapplication, I would like to render resolution-free GUI widgets described in SVG.
在pyGame应用程序中,我想渲染 SVG 中描述的无分辨率 GUI 小部件。
What tool and/or library can I use to reach this goal ?
我可以使用什么工具和/或库来达到这个目标?
(I like the OCEMP GUItoolkit but it seems to be bitmap dependent for its rendering)
(我喜欢OCEMP GUI工具包,但它的渲染似乎依赖于位图)
采纳答案by Johan Dahlin
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.
这是一个完整的例子,它结合了其他人的提示。它应该从当前目录呈现一个名为 test.svg 的文件。它在 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
回答by zgoda
The question is quite old but 10 years passed and there is new possibility that works and does not require librsvg
anymore. There is Cython wrapper over nanosvg libraryand it works:
这个问题已经很老了,但是 10 年过去了,有新的可能性可以工作并且不再需要librsvg
。nanosvg 库上有Cython 包装器,它可以工作:
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)
I found Cairo/rsvg solution too complicated to get to work because of dependencies are quite obscure to install.
我发现 Cairo/rsvg 解决方案太复杂而无法开始工作,因为安装依赖项非常模糊。
回答by Torsten Marek
回答by Alec Thomas
回答by Dickon Reed
回答by Pierre-Jean Coudert
Cairo cannot render SVG out of the box. It seems we have to use librsvg.
Cairo 无法立即渲染 SVG。看来我们必须使用 librsvg。
Just found those two pages:
刚找到那两页:
Something like this should probably work (render test.svgto test.png):
像这样的东西应该可以工作(将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")
回答by Dave
The last comment crashed when I ran it because svg.render_cairo() is expecting a cairo context and not a cairo surface. I created and tested the following function and it seems to run fine on my system.
最后一条评论在我运行时崩溃了,因为 svg.render_cairo() 期望的是 cairo 上下文而不是 cairo 表面。我创建并测试了以下函数,它似乎在我的系统上运行良好。
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
回答by goncalopp
Based on other answers, here's a function to read a SVG file into a pygame image - including correcting color channel order and scaling:
根据其他答案,这里有一个将 SVG 文件读入 pygame 图像的函数 - 包括校正颜色通道顺序和缩放:
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