2010-02-23 14 views
7

Quiero rendir partes de un archivo SVG por su nombre, pero para la vida de mí no puedo encontrar la manera de hacerlo (usando GTK + python).¿Cómo se renderiza partes * * de un archivo SVG?

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 se puede seguir hacia abajo en http://svg-cards.sourceforge.net/)

En su sitio, David, dice:

puede dibujar una tarjeta, ya sea por haciendo que el archivo en un mapa de píxeles y recorte cada tarjeta de forma manual o mediante 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é a qué se refiere con una interfaz DOM. He hecho un poco de búsqueda y el mejor resultado me encontré con que parece encajar lo que yo quiero hacer es: Sin embargo

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

en cuenta que se trata de Qt y 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?

Respuesta

9

La biblioteca GTK para la prestación de SVG se llama rsvg. Tiene enlaces Python, pero ellos son indocumentados, y no envolver los rsvg_handle_get_pixbuf_sub() y rsvg_handle_render_cairo_sub() funciones que normalmente se utiliza para ese fin en C. Esto es lo que tiene que hacer por lo que yo puedo decir. Extrae el nodo XML como sugirió Adam Crossland. Para hacerlo, hay 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 quieres que en un gtk.Image, de lo contrario hacer algo más con el pixbuf. También puede procesar a un contexto Cairo con handle.render_cairo(cr) donde cr es su contexto Cairo.

EDIT:

Lo sentimos, no he leído los enlaces Python con suficiente atención al principio.Los _sub() funciones se implementan utilizando el argumento id=, por lo que su programa puede reducirse a 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 lienzo de SVG y está recortada en el tamaño de la pantalla (por eso imprimí el 3 de diamantes en lugar del as de tréboles que está en la esquina). Así que todavía tendrás para encontrar la forma de recortar el pixbuf alrededor de la tarjeta que desea, pero eso no debería ser demasiado difícil.

+0

De hecho, también intenté de esta manera y no pude entender por qué estaba haciendo lo que estaba haciendo (de ahí que trate de encontrar otras soluciones para ver si obtengo un resultado similar). A pesar de que el tamaño de la ventana es del tamaño de todo el lienzo SVG, esta solución responde a mi pregunta (mientras, por supuesto, plantea otra pregunta). :) –

+0

Esto fue súper útil, aunque habría sido útil más ayuda. Para representar parte de una imagen SVG puedes usar handle.render_cairo (cr = c, id = "# layer_5") donde "c" es un contexto de cairo. La parte que no era del todo obvia para mí es que se requiere el "#" al comienzo de la identificación. Mi SVG tiene identificadores como 'id = "layer_1"' y puedo renderizar capas individuales con render_cairo (cr = c, id = "# layer_1") – bodgesoc

2

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

+0

¿Cómo representa el nodo XML? –

0

Puede hacerlo mediante la edición de la etiqueta. Edite ancho y alto, establezca el atributo viewBox en el elemento svg principal en el rectángulo que desee, renderice, repita.

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

+0

Esto no me ayuda a recuperar partes del archivo SVG por nombre y luego renderizarlas. –

+0

Es posible que pueda obtener el cuadro delimitador para las partes con nombre del archivo SVG y configurar el viewBox en consecuencia. – joeforker

1

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