如何渲染 svg 文件的*部分*?

发布于 2024-08-22 21:11:56 字数 1750 浏览 5 评论 0原文

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

当然,它不起作用。

我缺少什么?

I want to render parts of a svg file by name but for the life of me I cannot figure out how to do so (using python + gtk).

Here's the svg file in question: http://david.bellot.free.fr/svg-cards/files/SVG-cards-2.0.1.tar.gz (Update: this file no longer exists, but you can track it down at http://svg-cards.sourceforge.net/)

On his site, David, says:

You can draw a card either by
rendering the file onto a pixmap and
clipping each card manually or by
using the card's name through a DOM
interface. All cards are embedded into
a SVG group.

I don't know what he means by a DOM interface. I have done some searching and the best result I found that seems to fit what I want to do is:

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"));

Notice however that it is for Qt and is not even written in python.

This is what I have so far:

#!/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()

It doesn't work, of course.

What am I missing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

恏ㄋ傷疤忘ㄋ疼 2024-08-29 21:11:56

用于渲染 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) 将其渲染到 Cairo 上下文,其中 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 而不是角落里的梅花 A 的原因。)所以你仍然会得到找到一些方法来裁剪你想要的卡周围的 pixbuf,但这应该不会太难。

The GTK library for rendering SVG is called RSVG. It has python bindings, but they are undocumented, and they don't wrap the rsvg_handle_get_pixbuf_sub() and rsvg_handle_render_cairo_sub() functions which you would normally use for that purpose in C. Here's what you have to do as far as I can tell. You extract the XML node as Adam Crossland suggested. To render it, you have to do something like this:

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())

That's if you want it in a gtk.Image, otherwise do something else with the pixbuf. You can also render it to a Cairo context with handle.render_cairo(cr) where cr is your Cairo context.

EDIT:

Sorry, I didn't read the python bindings closely enough at first. The _sub() functions are implemented using the id= argument, so your program can boil down to this:

#!/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()

I tested this and it works. However, the window is the size of the entire SVG canvas, and is clipped to the screen size (which is why I rendered the 3 of diamonds instead of the ace of clubs which is up in the corner.) So you'll still have to find some way to crop the pixbuf around the card that you want, but that shouldn't be too hard.

千寻… 2024-08-29 21:11:56

这是我对裁剪空白问题的回答。这是一个粗糙的黑客,但效果很好。对于任何使用 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", {})

Here's my answer to the cropping blank space problem. It's a rough hack but it worked great. This would also serve as a good starting point to get cards for anyone making a card game in 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", {})
最笨的告白 2024-08-29 21:11:56

这里有点挖坟,但 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()

Grave-digging a little bit here, but the answer by ptomato from 2010 also works now in 2019 for Gtk3 with some slight modifications. The below code will render only the 3 of diamonds 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()
小傻瓜 2024-08-29 21:11:56

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

I believe that what he means by 'through a DOM interface' is that since SVG is XML, you could load the SVG file in minidom, or some other Python XML parser, and extract the XML node with the specific name that you are looking for. That XML node should represent an item that can be rendered.

赠佳期 2024-08-29 21:11:56

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

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

You can do it by editing the tag. Edit width and height, set the viewBox attribute on the main svg element to the rectangle you want, render, repeat.

See How to show a subsection or "slice" of an SVG graphic? and http://dingoskidneys.com/~dholth/svg/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文