Как я представляю *части* 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/),

На его сайте, David, говорит:

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

Это не работает, конечно.

Что я пропускаю?

6
задан brainjam 2 October 2010 в 19:54
поделиться

4 ответа

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

EDIT:

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

9
ответ дан 9 December 2019 в 20:42
поделиться

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

2
ответ дан 9 December 2019 в 20:42
поделиться

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

См. Как показать подраздел или «фрагмент» SVG-графики? и http://dingoskidneys.com/~dholth/svg/

0
ответ дан 9 December 2019 в 20:42
поделиться

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

Похожие вопросы: