¿Cómo renderizo * partes * de un archivo svg?

Quiero representar partes de un archivo svg por nombre, pero por mi vida no puedo averiguar cómo hacerlo (usando python + gtk).

Aquí está el archivo svg en cuestión: http://david.bellot.free.fr/svg-cards/files/SVG-cards-2.0.1.tar.gz ( Actualización: este archivo ya no existe, pero puede rastrearlo abajo en http://svg-cards.sourceforge.net/ )

En su sitio, David, dice:

Puede dibujar una tarjeta representando el archivo en un mapa de píxeles y recortando cada tarjeta manualmente o usando el nombre de la tarjeta a través de una interfaz DOM. Todas las tarjetas están integradas en un grupo SVG.

No sé lo que quiere decir con una interfaz DOM. He hecho algunas búsquedas y el mejor resultado que encontré que parece encajar con lo que quiero hacer es:

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

Sin embargo, tenga en cuenta que es para Qt y que ni siquiera está escrito en python.

Esto es lo que tengo hasta ahora:

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

No funciona, por supuesto.

¿Qué me estoy perdiendo?

La biblioteca GTK para renderizar SVG se llama RSVG. Tiene enlaces de Python, pero no están documentados, y no envuelven las rsvg_handle_get_pixbuf_sub() y rsvg_handle_render_cairo_sub() que normalmente usaría para ese propósito en C. Esto es lo que tiene que hacer todo lo que puedo decir. Extrae el nodo XML como sugirió Adam Crossland. Para renderizarlo, tienes que hacer algo como esto:

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

Eso es si lo quieres en una imagen de gtk.Image . De lo contrario, haz algo más con el pixbuf. También puede representarlo en un contexto de Cairo con handle.render_cairo(cr) donde cr es su contexto de Cairo.

EDITAR:

Lo siento, no leí los enlaces de python lo suficientemente cerca al principio. Las funciones _sub() se implementan usando el argumento id= , por lo que su progtwig puede resumirse en esto:

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

He probado esto y funciona. Sin embargo, la ventana es del tamaño de todo el canvas de SVG y está recortada al tamaño de la pantalla (por lo que representé el 3 de diamantes en lugar del as de palos que está en la esquina). para encontrar alguna forma de recortar el pixbuf alrededor de la tarjeta que quieras, pero eso no debería ser demasiado difícil.

Creo que lo que quiere decir con ‘a través de una interfaz DOM’ es que, dado que SVG es XML, puede cargar el archivo SVG en minidom , o algún otro analizador de Python XML, y extraer el nodo XML con el nombre específico que está buscando . Ese nodo XML debe representar un elemento que se puede representar.

Aquí está mi respuesta al problema del espacio en blanco de recorte. Es un truco duro pero funcionó muy bien. Esto también serviría como un buen punto de partida para obtener tarjetas para cualquiera que esté haciendo un juego de cartas en 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", {}) 

Puedes hacerlo editando la etiqueta. Edite el ancho y el alto, establezca el atributo viewBox en el elemento svg principal al rectángulo que desea, renderice, repita.

Consulte ¿Cómo mostrar una subsección o “sección” de un gráfico SVG? y http://dingoskidneys.com/~dholth/svg/

Cavar un poco aquí, pero la respuesta de ptomato de 2010 también funciona ahora en 2019 para Gtk3 con algunas modificaciones leves. El siguiente código mostrará solo el 3 de los diamantes 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()