Displaying SVG in tkinter using cairo and rsvg

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

Arndt Roger Schneider

Martin said:
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:
[snip]

raster images from SVG:
There are multiple methods to convert a scalable vector graphic
into a bitmap.
In addition to cairo, librsvg and rsvg imageMagick contains a
vector graphic format similar to svg--gradients and transparency
are problematic for this approach, but its a while since I had
looked into it...

My product Jeszra imports svg into Tk(using tkpath
http://jeszra.sourceforge.net/jeszra/Jeszra_TechnicalNotes.html#d0e10279
), preserving it as a vector graphics.
There are, of course, limitations to what can be preserved in Tk:

http://jeszra.sourceforge.net/jeszra/SVG_Import.html

The other way is much simpler to convert a Tk graphics into
svg, which is also implemented in Jeszra.
All svg graphics on http://jeszra.sourceforge.net and
http://gestaltitems.sourceforge.net are generated by Jeszra from
Tk (there are some hundred graphics)...

The generator API is open and a draft documentation is online at:
http://jeszra.sourceforge.net/api/ch01s04.html
http://jeszra.sourceforge.net/api/index.html

Jeszra API Concerning svg:
http://jeszra.sourceforge.net/api/ch04.html
http://jeszra.sourceforge.net/api/ch05.html
http://jeszra.sourceforge.net/api/ch06.html
http://jeszra.sourceforge.net/api/ch07.html
http://jeszra.sourceforge.net/api/ch08.html

Here is an overview about Jeszra, SVG and Tk:
http://jeszra.sourceforge.net/api/pictures/overview.svg


The svg on those page gets on-demand converted into flash,
for the internet explorer.

Is there anyting else You want to know about svg?

-roger
 
M

Martin P. Hellwig

On 02/16/11 09:04, Arndt Roger Schneider wrote:
raster images from SVG:
There are multiple methods to convert a scalable vector graphic
into a bitmap.
In addition to cairo, librsvg and rsvg imageMagick contains a
vector graphic format similar to svg--gradients and transparency
are problematic for this approach, but its a while since I had
looked into it...

My product Jeszra imports svg into Tk(using tkpath
http://jeszra.sourceforge.net/jeszra/Jeszra_TechnicalNotes.html#d0e10279
), preserving it as a vector graphics.
There are, of course, limitations to what can be preserved in Tk:

tkpath does not seem to come standard with Python's tk version when I
looked into it a couple of years ago, but maybe it has now?

Is there anyting else You want to know about svg?

No not really :), I just wanted to display a SVG in tkinter with the
minimal amount of external dependencies, since I have achieved that I
thought I share my experience, so that the next time someone google
tkinter and display svg it will return something that (well at least of
the time of this writing) worked.

Thanks for the info though.
 
A

Arndt Roger Schneider

Martin said:
On 02/16/11 09:04, Arndt Roger Schneider wrote:
[snip]

tkpath does not seem to come standard with Python's tk version when I
looked into it a couple of years ago, but maybe it has now?
tk canvas and tkpath share the same interface, the first tkpath was
a plugin into the tk canvas. A tkinter wrapper class will
be a simple subclass of tk canvas introducing the new item types:
path, ppolygone, polyline, circle, elipsis, pimage, prect, ptext, group
and for tkpath 0.3 three
additional messages for: style, gradient and distance, that's all
~50 lines of code.
No not really :), I just wanted to display a SVG in tkinter with the
minimal amount of external dependencies, since I have achieved that I
thought I share my experience, so that the next time someone google
tkinter and display svg it will return something that (well at least of
the time of this writing) worked.

Well CAIRO is sort of a shifting target...
--currently I am stuck with PPC and new CAIRO versions cannot longer
being built on it anymore :-(--

CAIRO can be real pain on non-X11-linux platforms. ImageMagick
is simpler than CAIRO cross-platform wise.

-roger
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,007
Latest member
obedient dusk

Latest Threads

Top