6

我想按名称渲染 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()

当然,它不起作用。

我错过了什么?

4

5 回答 5

9

用于渲染 SVG 的 GTK 库称为 RSVG。它具有 python 绑定,但它们没有记录,并且它们不包装您通常在 C 中用于该目的的rsvg_handle_get_pixbuf_sub()and函数。据我所知,这是您必须做的。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())

那是如果你想要它在 a 中gtk.Image,否则用 pixbuf 做其他事情。您还可以将其渲染到 Cairo 上下文,handle.render_cairo(cr)其中cr您的 Cairo 上下文在哪里。

编辑:

抱歉,一开始我没有仔细阅读 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,但这不应该太难。

于 2010-02-23T21:34:57.077 回答
2

我相信他所说的“通过 DOM 接口”的意思是,由于 SVG 是 XML,因此您可以在minidom或其他 Python XML 解析器中加载 SVG 文件,并提取具有您正在寻找的特定名称的 XML 节点. 该 XML 节点应该表示可以呈现的项目。

于 2010-02-23T20:03:23.327 回答
1

这是我对裁剪空白空间问题的回答。这是一个粗略的hack,但效果很好。这也可以作为一个很好的起点,让任何用 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", {})
于 2010-05-26T03:48:58.237 回答
1

在这里挖了一点坟墓,但是 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()
于 2019-01-17T21:32:04.247 回答
0

您可以通过编辑标签来做到这一点。编辑宽度和高度,将主 svg 元素上的 viewBox 属性设置为您想要的矩形,渲染,重复。

请参阅如何显示 SVG 图形的小节或“切片”?http://dingoskidneys.com/~dholth/svg/

于 2010-02-23T20:13:29.723 回答