I want to be able to open SVG files in tkinter. The answer I'm using right now converts the SVG into a PNG before showing it in tkinter, but since I want to be to resize it without losing quality, I need a better answer.
-
By “open” do you mean “display”, or just open it like a text file to read its contents? – Bryan Oakley Nov 13 '20 at 22:17
-
Tkinter cannot handle SVG, so if you don't want to lose quality, you will need to convert again your original SVG each time you resize it. – j_4321 Nov 13 '20 at 22:20
-
@BryanOakley I do mean display. – DUO Labs Nov 13 '20 at 22:21
-
@j_4321 Are there any scalable graphic formats that tkinter can handle as scalable? – DUO Labs Nov 13 '20 at 22:30
-
Tkinter has no support for svg – Bryan Oakley Nov 13 '20 at 22:35
-
@BryanOakley Well, are there any scalable graphic formats that tkinter can handle as scalable? – DUO Labs Nov 13 '20 at 22:53
-
@DUO No, tkinter cannot not handle any kind of vector graphics format – j_4321 Nov 13 '20 at 23:05
-
No, tkinter has no support for scalable graphic formats. – Bryan Oakley Nov 13 '20 at 23:16
-
1But some kind of svg support is going to be added to next version of Tk (8.7): https://core.tcl-lang.org/tips/doc/trunk/tip/507.md, otherwise you can try to use the library [tksvg](https://wiki.tcl-lang.org/page/tksvg) but you will need to use it through the tcl interpreter – j_4321 Nov 13 '20 at 23:20
-
@j_4321 Good to know, thank you. – DUO Labs Nov 14 '20 at 00:18
2 Answers
Some basic svg support will be part of tk 8.7 (https://core.tcl-lang.org/tips/doc/trunk/tip/507.md).
But to add svg support to tk 8.6, it is necessary to install an extra package like tksvg. So, first install tksvg, following the instructions from here. Then you can create a PhotoImage
from a svg file but you need to load tksvg in the tcl interpreter. I wrote a quick python wrapper for tksvg:
import tkinter as tk
class SvgImage(tk.PhotoImage):
"""Widget which can display images in PGM, PPM, GIF, PNG format."""
_tksvg_loaded = False
_svg_options = ['scale', 'scaletowidth', 'scaletoheight']
def __init__(self, name=None, cnf={}, master=None, **kw):
# load tksvg
if not SvgImage._tksvg_loaded:
if master is None:
master = tk._default_root
if not master:
raise RuntimeError('Too early to create image')
master.tk.eval('package require tksvg')
SvgImage._tksvg_loaded = True
# remove specific svg options from keywords
svgkw = {opt: kw.pop(opt, None) for opt in self._svg_options}
tk.PhotoImage.__init__(self, name, cnf, master, **kw)
# pass svg options
self.configure(**svgkw)
def configure(self, **kw):
svgkw = {opt: kw.pop(opt) for opt in self._svg_options if opt in kw}
# non svg options
if kw:
tk.PhotoImage.configure(self, **kw)
# svg options
options = ()
for k, v in svgkw.items():
if v is not None:
options = options + ('-'+k, str(v))
self.tk.eval('%s configure -format {svg %s}' % (self.name, ' '.join(options)))
So SvgImage
is like a PhotoImage
but it has the additional options (only one of them can be specified since they are three different way of specifying the image size):
scale
scaletowidth
: width in pixelscaletoheight
: height in pixel
Here is an example:
root = tk.Tk()
def rescale():
global scale
scale += 0.5
img.configure(scale=scale)
scale = 0.5
img = SvgImage(master=root, file='/path/to/file.svg', scale=scale)
tk.Button(root, image=img, command=rescale).pack()
root.mainloop()

- 15,431
- 3
- 34
- 61
I think that there is no way of doing this without losing quality resolutions, but if svglib was not good enough maybe cairo can do it better. Try the code bellow. It has the advantage that you don't really need the image as a png file, but since PIL does not handle svg you have to convert it anyway:
from io import BytesIO
import cairosvg
from PIL import Image
out = BytesIO()
cairosvg.svg2png(url='path/to/svg', write_to=out)
image = Image.open(out)

- 1,331
- 1
- 5
- 16
-
-
Yes. It only handles with specific image object. You normally use PIL to create such objects but PIL don't handle SVG – Flavio Moraes Nov 13 '20 at 23:10