How do I render *parts* of a svg file?

前端 未结 5 1161
借酒劲吻你
借酒劲吻你 2021-01-01 00:30

I want to render parts of a svg file by name but for the life of me I cannot figure out how to do so (using python + gtk).

Here\'s the svg file in question: http://d

相关标签:
5条回答
  • 2021-01-01 01:04

    The GTK library for rendering SVG is called RSVG. It has python bindings, but they are undocumented, and they don't wrap the rsvg_handle_get_pixbuf_sub() and rsvg_handle_render_cairo_sub() functions which you would normally use for that purpose in C. Here's what you have to do as far as I can tell. You extract the XML node as Adam Crossland suggested. To render it, you have to 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())
    

    That's if you want it in a gtk.Image, otherwise do something else with the pixbuf. You can also render it to a Cairo context with handle.render_cairo(cr) where cr is your Cairo context.

    EDIT:

    Sorry, I didn't read the python bindings closely enough at first. The _sub() functions are implemented using the id= argument, so your program can boil down to this:

    #!/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 clipped to the screen size (which is why I rendered the 3 of diamonds instead of the ace of clubs which is up in the corner.) So you'll still have to find some way to crop the pixbuf around the card that you want, but that shouldn't be too hard.

    0 讨论(0)
  • 2021-01-01 01:14

    Grave-digging a little bit here, but the answer by ptomato from 2010 also works now in 2019 for Gtk3 with some slight modifications. The below code will render only the 3 of diamonds 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 讨论(0)
  • 2021-01-01 01:19

    Here's my answer to the cropping blank space problem. It's a rough hack but it worked great. This would also serve as a good starting point to get cards for anyone making a card game 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", {})
    
    0 讨论(0)
  • 2021-01-01 01:25

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

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

    0 讨论(0)
  • 2021-01-01 01:26

    I believe that what he means by 'through a DOM interface' is that since SVG is XML, you could load the SVG file in minidom, or some other Python XML parser, and extract the XML node with the specific name that you are looking for. That XML node should represent an item that can be rendered.

    0 讨论(0)
提交回复
热议问题