Displaying SVG in tkinter using cairo and rsvg

Martin P. Hellwig martin.hellwig at dcuktec.org
Tue Feb 15 15:01:49 EST 2011


Hi all,

Information on using tkinter for displaying an svg image seems a bit low 
spread on the Internet. I recently played around with pygame and svg and 
realized, hold on this can be done with tk too. So I thought I post a 
little example for future generations :-) (and also have stored at 
http://dcuktec.googlecode.com/hg/source/examples/cairo_rsvg_tkinter.py).

So here it is if you are interested:

---
#! /usr/bin/env python
"""
Tkinter example for displaying SVG in a PhotoImage class using cairo and 
rsvg.
Note that this is relatively slow, this is mainly due to converting the 
cairo
surface data to the appropriate rgb values and putting each pixel in the
PhotoImage class.
"""
import cairo
import rsvg
# I had a bit of trouble finding the rsvg python wrapper, turns out it 
is part
# of the GnomePythonDesktop package, windows users are even less 
supported see:
# http://cairographics.org/cairo_rsvg_and_python_in_windows/ to get it 
working.
import Tkinter

def _alpha_blending(rgba, back):
     "Return a rgb tuple composed from a rgba and back(ground) tuple/list."
     paired = zip(rgba[:-1], back)
     alpha = rgba[-1]
     tmp = list()
     for upper, lower in paired:
         blend = (((255 - alpha) * lower) + (alpha * upper)) / 255
         tmp.append(blend)

     return(tuple(tmp))

def convert(bgra_buffer, width, height):
     "Convert bgra buffer to photoimage put"
     idx = 0
     end = len(bgra_buffer)
     arguments = list()

     while idx < end:
         rgba = (ord(bgra_buffer[idx + 2]),
                 ord(bgra_buffer[idx + 1]),
                 ord(bgra_buffer[idx + 0]),
                 ord(bgra_buffer[idx + 3]))
         back = (255, 255, 255)
         rgb = _alpha_blending(rgba, back)
         arguments += rgb
         idx += 4

     template = ' '.join(height *['{%s}' % (' 
'.join(width*["#%02x%02x%02x"]))])
     return(template % tuple(arguments))


def photoimage_from_svg(file_path_name):
     "Return a Tkinter.PhotoImage with the content set to the rendered 
SVG."
     svg = rsvg.Handle(file=file_path_name)
     width, height = svg.get_dimension_data()[:2]
     surface = cairo.ImageSurface(cairo.FORMAT_RGB24, int(width), 
int(height))
     context = cairo.Context(surface)
     svg.render_cairo(context)
     image = Tkinter.PhotoImage(width=width, height=height)
     data = convert(surface.get_data(), width, height)
     image.put(data)
     return(image)

if __name__ == '__main__':
     SVG = """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
     <svg
        xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
        xmlns:svg="http://www.w3.org/2000/svg"
        xmlns="http://www.w3.org/2000/svg"
        id="test" version="1.1" width="900" height="600">
        <rect id="red"    width="300" height="300" x="000" y="000"
               style="fill:#ff0000;fill-opacity:1.0;stroke:none" />
        <rect id="green"  width="300" height="300" x="300" y="000"
               style="fill:#00ff00;fill-opacity:1.0;stroke:none" />
        <rect id="blue"   width="300" height="300" x="600" y="000"
               style="fill:#0000ff;fill-opacity:1.0;stroke:none" />
        <rect id="black"  width="300" height="300" x="000" y="300"
                style="fill:#000000;fill-opacity:1.0;stroke:none" />
        <rect id="grey"  width="300" height="300" x="300" y="300"
                style="fill:#000000;fill-opacity:0.5;stroke:none" />
        <rect id="white" width="300" height="300" x="600" y="300"
               style="fill:#ffffff;fill-opacity:1.0;stroke:none" />
     </svg>"""
     import os, tempfile
     #
     PATH = tempfile.mkstemp()[1]
     OPEN = open(PATH, 'w')
     OPEN.writelines(SVG)
     OPEN.close()
     ROOT = Tkinter.Tk()
     #
     IMAGE = photoimage_from_svg(PATH)
     #
     os.remove(PATH)
     BUTTON = Tkinter.Button(ROOT, image=IMAGE)
     BUTTON._photoimage = IMAGE
     BUTTON.grid()
     Tkinter.mainloop()
---
-- 
mph



More information about the Python-list mailing list