我想通过名称呈现svg文件的一部分但是对于我的生活我无法弄清楚如何这样做(使用python + gtk)。
以下是相关的svg文件:http://david.bellot.free.fr/svg-cards/files/SVG-cards-2.0.1.tar.gz(更新:此文件已不存在,但您可以在http://svg-cards.sourceforge.net/跟踪它)
在他的网站上,大卫说:
您可以通过以下方式绘制卡片 将文件渲染到像素图上 手动或通过裁剪每张卡 通过DOM使用卡的名称 接口。所有卡都嵌入其中 一个SVG小组。
我不知道DOM接口意味着什么。我做了一些搜索,我发现的最好的结果似乎符合我想做的事情:
QSvgRenderer *renderer = new QSvgRenderer(QLatin1String("SvgCardDeck.svg"));
QGraphicsSvgItem *black = new QGraphicsSvgItem();
QGraphicsSvgItem *red = new QGraphicsSvgItem();
black->setSharedRenderer(renderer);
black->setElementId(QLatin1String("black_joker"));
red->setSharedRenderer(renderer);
red->setElementId(QLatin1String("red_joker"));
但请注意,它适用于Qt,甚至不用python编写。
这是我到目前为止所做的:
#!/usr/bin/env python
from __future__ import absolute_import
import cairo
import gtk
import rsvg
from xml import xpath
from xml.dom import minidom
window = gtk.Window()
window.set_title("Foo")
window.set_size_request(256, 256)
window.set_property("resizable", False)
window.set_position(gtk.WIN_POS_CENTER)
window.connect("destroy", gtk.main_quit)
window.show()
document = minidom.parse("cards.svg")
element = xpath.Evaluate("//*[@id='1_club']", document)[0]
xml = element.toxml()
svg = rsvg.Handle()
svg.write(xml)
pixbuf = svg.get_pixbuf()
image = gtk.Image()
image.set_from_pixbuf(pixbuf)
image.show()
window.add(image)
gtk.main()
当然不行。
我错过了什么?
答案 0 :(得分:9)
用于渲染SVG的GTK库称为RSVG。它有python绑定,但它们没有文档,并且它们不包含你在C中通常用于此目的的rsvg_handle_get_pixbuf_sub()
和rsvg_handle_render_cairo_sub()
函数。这就是你必须要做的事情。可以告诉。您可以像Adam Crossland建议的那样提取XML节点。要渲染它,你必须做这样的事情:
import gtk
import rsvg
handle = rsvg.Handle()
handle.write(buffer=xml_data)
# xml_data is the XML string for the object you want
image = gtk.Image()
image.set_from_pixbuf(handle.get_pixbuf())
如果你想要它在gtk.Image
,那么用pixbuf做其他事情。您还可以使用handle.render_cairo(cr)
将其呈现给开罗上下文,其中cr
是您的开罗背景。
修改强>
抱歉,我最初没有仔细阅读python绑定。 _sub()
函数是使用id=
参数实现的,因此您的程序可以归结为:
#!/usr/bin/env python
import gtk
import rsvg
window = gtk.Window()
window.set_title("Foo")
window.connect("destroy", gtk.main_quit)
window.show()
svg = rsvg.Handle(file='cards.svg')
pixbuf = svg.get_pixbuf(id='#3_diamond')
image = gtk.Image()
image.set_from_pixbuf(pixbuf)
image.show()
window.add(image)
gtk.main()
我测试了这个并且它有效。然而,窗口是整个SVG画布的大小,并被剪裁到屏幕大小(这就是为什么我渲染了3颗钻石而不是角落里的俱乐部的ace。)所以你仍然会有找到一些方法来裁剪你想要的卡片周围的pixbuf,但这不应该太难。
答案 1 :(得分:2)
我相信'通过DOM接口'的意思是,由于SVG是XML,您可以在 minidom 或其他一些Python XML解析器中加载SVG文件,并提取XML具有您要查找的特定名称的节点。该XML节点应表示可以呈现的项目。
答案 2 :(得分:1)
这是我对裁剪空白问题的答案。这是一个粗糙的黑客,但它工作得很好。对于任何在python中制作纸牌游戏的人来说,这也是一个很好的起点。
import gtk
import rsvg
svg = rsvg.Handle(file="/usr/share/gnome-games-common/cards/gnomangelo_bitmap.svg")
w, h = 202.5, 315
card_names = map(str, range(1,11)) + ["jack", "queen", "king"]
suites = ["club", "diamond", "heart", "spade"]
specials = [{"name":"black_joker","x":0, "y":4}, {"name":"red_joker","x":1, "y":4}, {"name":"back","x":2, "y":4}]
for suite_number, suite in enumerate(suites):
for card_number, card in enumerate(card_names):
print "processing", suite, card, '#'+card+'_'+suite
pixbuf = svg.get_pixbuf(id='#'+card+'_'+suite)
pixbuf.subpixbuf(int(w*card_number), int(h*suite_number), int(w), int(h)).save("./"+card+"_"+suite+".png","png", {})
for special in specials:
print "processing", special["name"]
pixbuf = svg.get_pixbuf(id='#'+special["name"])
card_number = special["x"]
suite_number = special["y"]
pixbuf.subpixbuf(int(w*card_number), int(h*suite_number), int(w), int(h)).save("./"+special["name"]+".png","png", {})
答案 3 :(得分:0)
您可以通过编辑标签来完成。编辑宽度和高度,将主svg元素上的viewBox属性设置为所需的矩形,渲染,重复。
请参阅How to show a subsection or "slice" of an SVG graphic?和http://dingoskidneys.com/~dholth/svg/
答案 4 :(得分:0)
在这里进行了一些深入的挖掘,但是ptomato从2010年开始的答案现在也可以在2019年对Gtk3进行一些细微的修改。以下代码将仅呈现3个钻石的svg ID。
#!/usr/bin/env python
import gi
gi.require_version('Gtk', '3.0')
gi.require_version('Rsvg', '2.0')
from gi.repository import Gtk, Rsvg
svg = Rsvg.Handle.new_from_file('svg-cards.svg')
pixbuf = svg.get_pixbuf_sub('#3_diamond')
image = Gtk.Image()
image.set_from_pixbuf(pixbuf)
image.show()
window = Gtk.Window()
window.set_title("Foo")
window.connect("destroy", Gtk.main_quit)
window.show()
window.add(image)
Gtk.main()