M
Martin P. Hellwig
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()
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()