Как мне отрендерить * части * файла SVG? - PullRequest
6 голосов
/ 23 февраля 2010

Я хочу визуализировать части файла 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()

Конечно, это не работает.

Чего мне не хватает?

Ответы [ 5 ]

9 голосов
/ 24 февраля 2010

Библиотека 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. Вы также можете отобразить его в каирском контексте с помощью handle.render_cairo(cr), где cr - это ваш каирский контекст.

EDIT:

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

2 голосов
/ 23 февраля 2010

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

1 голос
/ 26 мая 2010

Вот мой ответ на проблему обрезки пустого пространства. Это грубый взлом, но он работал отлично. Это также послужит хорошей отправной точкой для получения карточек для всех, кто делает карточную игру на питоне.

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", {})
0 голосов
/ 18 января 2019

Здесь можно немного покопаться, но ответ от 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()
0 голосов
/ 23 февраля 2010

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

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

...