Reputation: 159
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.
Upvotes: 3
Views: 3243
Reputation: 16169
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 pixelHere 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()
Upvotes: 5
Reputation: 1351
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)
Upvotes: 1