عرض SVG في تطبيق PyGame
سؤال
في pyGame التطبيق، أرغب في عرض عناصر واجهة المستخدم الرسومية (GUI) بدون دقة وضوح والموضحة في SVG.
ما الأداة و/أو المكتبة التي يمكنني استخدامها للوصول إلى هذا الهدف؟
(انا احب ال واجهة المستخدم الرسومية OCEMP مجموعة أدوات ولكن يبدو أنها تعتمد على الصورة النقطية لعرضها)
المحلول
هذا مثال كامل يجمع تلميحات من أشخاص آخرين هنا.يجب أن يعرض ملفًا يسمى 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
نصائح أخرى
السؤال قديم جدًا ولكن مرت 10 سنوات وهناك إمكانية جديدة تعمل ولا تتطلب ذلك librsvg
أي أكثر من ذلك.هنالك غلاف Cython فوق مكتبة nanosvg ويعمل:
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)
لقد وجدت أن حل القاهرة/rsvg معقد جدًا بحيث لا يمكن تشغيله نظرًا لأن التبعيات غامضة تمامًا بحيث لا يمكن تثبيتها.
أدرك أن هذا لا يجيب بالضبط على سؤالك، ولكن هناك مكتبة تسمى سكويرتل من شأنها أن تعرض ملفات SVG باستخدام Pyglet أو PyOpenGL.
pygamesvg يبدو أنه يفعل ما تريد (على الرغم من أنني لم أجربه).
لا تستطيع القاهرة عرض SVG خارج الصندوق.يبدو أنه يتعين علينا استخدام librsvg.
وجدت للتو هاتين الصفحتين:
من المحتمل أن يعمل شيء مثل هذا (render test.svg ل اختبار.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")
لقد تعطل التعليق الأخير عندما قمت بتشغيله لأن svg.render_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
استنادًا إلى الإجابات الأخرى، إليك وظيفة لقراءة ملف 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