How to visualize * parts * of an svg file?

I want to display parts of an svg file by name, but for life I can’t figure out how to do this (using python + gtk).

Here is the svg file: http://david.bellot.free.fr/svg-cards/files/SVG-cards-2.0.1.tar.gz ( Update: this file no longer exists, but you can track it on http : //svg-cards.sourceforge.net/ )

On his website, David says:

You can draw a map rendering a file on pixmap and clipping each card manually or by using the map name through the DOM interface. All cards are built into the SVG group.

I do not know what it means by the DOM interface. I did some searches and the best result I found, which seems to match what I want to do:

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

Please note that this is for Qt and is not even written in python.

This is what I still have:

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

This does not work, of course.

What am I missing?

+6
python svg gtk cairo
source share
5 answers

The GTK library for SVG rendering is called RSVG. It has python bindings, but they are undocumented, and they do not wrap the rsvg_handle_get_pixbuf_sub() and rsvg_handle_render_cairo_sub() functions that you usually used for this purpose in C. This is what you should do as far as I can tell. You are retrieving the XML node, as suggested by Adam Crossland. To do this, you should do something like this:

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

This is if you want it in gtk.Image , otherwise do something else with pixbuf. You can also display it in the context of Cairo with handle.render_cairo(cr) , where cr is your Cairo context.

EDIT:

Sorry, I did not read python bindings very well. The _sub() functions _sub() implemented using the id= argument, so your program may boil down to the following:

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

I tested this and it works. However, the window is the size of the entire SVG canvas and is cropped to the screen size (which is why I selected 3 diamonds instead of the ace of clubs, which is in the corner.) So you will still have to find a way to crop the pixbuf around the map, which you want, but it should not be too difficult.

+9
source share

I believe that what it means by the “DOM interface” is that since SVG is XML, you can load the SVG file in a mini-minim or some other Python XML parser and extract the XML node with a specific name that you are looking for. This XML node should represent an object that can be displayed.

+2
source share

Here is my answer to the problem with empty cropping space. This is a rough hack, but it did a great job. It will also serve as a good starting point for getting cards for those who make card games in 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
source share

You can do this by editing the tag. Change the width and height, set the viewBox attribute in the svg main element to the rectangle you want, render, repeat.

See How to show a subsection or “slice”. SVG graphics? and http://dingoskidneys.com/~dholth/svg/

0
source share

You can dig a bit here, but the answer from ptomato from 2010 also works in 2019 for Gtk3 with some minor changes. The code below will only display 3 of the svg id diamonds.

 #!/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
source share

All Articles