Как отобразить * части * файла svg?

Я хочу отобразить части svg-файла по имени, но для жизни меня я не могу понять, как это сделать (используя python + gtk).

вот файл svg в вопросе:http://david.bellot.free.fr/svg-cards/files/SVG-cards-2.0.1.tar.gz (обновление: этот файл больше не существует, но вы можете отследить его вhttp://svg-cards.sourceforge.net/)

на своем сайте Давид говорит:

вы можете нарисовать карту либо рендеринг файла на pixmap и обрезка каждой карты вручную или использование имени карты через 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 ответов


библиотека GTK для рендеринга SVG называется RSVG. Он имеет привязки python, но они недокументированы, и они не обертывают rsvg_handle_get_pixbuf_sub() и rsvg_handle_render_cairo_sub() функции, которые вы обычно используете для этой цели в с. Вот, что вам нужно сделать, насколько я могу судить. Извлеките узел 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 это ваш Каирский контекст.

EDIT:

извините, сначала я недостаточно внимательно читал привязки python. The _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 из бубны вместо туза треф, который стоит в углу.) Таким образом, вам все равно придется найти способ обрезать pixbuf вокруг карты, которую вы хотите, но это не должно быть слишком сложно.


Я считаю, что он имеет в виду "через интерфейс DOM", что, поскольку SVG является XML, вы можете загрузить файл SVG в минидом или какой-либо другой синтаксический анализатор Python XML и извлеките узел XML с определенным именем, которое вы ищете. Этот XML-узел должен представлять элемент, который можно отобразить.


вот мой ответ на проблему обрезки пустого пространства. Это грубый взлом, но он отлично сработал. Это также послужит хорошей отправной точкой для получения карт для тех, кто делает карточную игру в 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", {})

вы можете сделать это путем редактирования тегов. Отредактируйте ширину и высоту, установите атрибут viewBox для основного элемента svg в нужный прямоугольник, визуализируйте, повторите.

посмотреть как показать подраздел или "срез" SVG-графики? и http://dingoskidneys.com / ~dholth / svg/