Putting .SVG images into tkinter Frame
Asked Answered
A

4

18

I have been trying to put the image from https://betacssjs.chesscomfiles.com/bundles/web/favicons/safari-pinned-tab.f387b3f2.svg into a Tkinter frame. I found from the post here that it is possible with the help from rsvg and cairo.

I was using python 3.6 on Windows 10. I got rsvg from here and cairo from here and then extracted the folders to the 'C:\Users...\site_packages' folder. They import fine but I cannot figure out how to use them. I tried using the code:

import tkinter as tk
main=tk.Tk()
frame=tk.Frame(main)
def svgPhotoImage(self,file_path_name):
        from PIL import Image,ImageTk
        import rsvg,cairo 
        svg = rsvg.Handle(file=file_path_name)
        width, height = svg.get_dimension_data()[:2]
            surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(width), int(height))
            context = cairo.Context(surface)
            #context.set_antialias(cairo.ANTIALIAS_SUBPIXEL)
            svg.render_cairo(context)
            tk_image=ImageTk.PhotoImage('RGBA')
            image=Image.frombuffer('RGBA',(width,height),surface.get_data(),'raw','BGRA',0,1)
            tk_image.paste(image)
            return(tk_image)
    tk_image=self.svgPhotoImage(filename)
    frame.configure(image=tk_image)

and

#rsvg.py
import os
try:
    import rsvg
    WINDOWS=False
except ImportError:
    print"Warning, could not import 'rsvg'"
    if os.name == 'nt':
        print "Detected windows, creating rsvg."
        #some workarounds for windows

        from ctypes import *

        l=CDLL('librsvg-2-2.dll')
        g=CDLL('libgobject-2.0-0.dll')
        g.g_type_init()

        class rsvgHandle():
            class RsvgDimensionData(Structure):
                _fields_ = [("width", c_int),
                            ("height", c_int),
                            ("em",c_double),
                            ("ex",c_double)]

            class PycairoContext(Structure):
                _fields_ = [("PyObject_HEAD", c_byte * object.__basicsize__),
                            ("ctx", c_void_p),
                            ("base", c_void_p)]

            def __init__(self, path):
                self.path = path
                error = ''
                self.handle = l.rsvg_handle_new_from_file(self.path,error)


            def get_dimension_data(self):
                svgDim = self.RsvgDimensionData()
                l.rsvg_handle_get_dimensions(self.handle,byref(svgDim))
                return (svgDim.width,svgDim.height)

            def render_cairo(self, ctx):
                ctx.save()
                z = self.PycairoContext.from_address(id(ctx))
                l.rsvg_handle_render_cairo(self.handle, z.ctx)
                ctx.restore()



        class rsvgClass():
            def Handle(self,file):
                return rsvgHandle(file)

        rsvg = rsvgClass()).
h = rsvg.Handle("box.svg")
s = cairo.ImageSurface(cairo.FORMAT_ARGB32, 100, 100)
ctx = cairo.Context(s)
h.render_cairo(ctx)

After trying those scripts, I kept getting the error message:

AttributeError: module 'rsvg' has no attribute 'Handle'

I am sure I did something wrong in the process but after hours of searching still could not figure out how to get it to work. I also tried installing pycairo (via pip) but got the error message

ERROR: Command "'c:\...\python36-32\python.exe' -u -c 'import setuptools, tokenize;__file__='"'"'C:\\...\\pip-install-peqhj3x1\\pycairo\\setup.py'"'"';f=getattr(tokenize, '"'"'open'"'"', open)(__file__);code=f.read().replace('"'"'\r\n'"'"', '"'"'\n'"'"');f.close();exec(compile(code, __file__, '"'"'exec'"'"'))' install --record 'C:\...\Temp\pip-record-jfozfbuc\install-record.txt' --single-version-externally-managed --compile" failed with error code 1 in C:\...\pip-install-peqhj3x1\pycairo\

I have no clue as to what to do now

EDIT: I was finally able to obtain pycairo from https://www.lfd.uci.edu/~gohlke/pythonlibs/ and now have it working. I finally got rsvg to not give me the error message above by referring here and got the nessary DLL files from here. Cairo is working fine but RSVG is creating a blank screen. I tried another 7-liner here and get the output of a blank file instead of a converted one. Evidently RSVG is not working and I think it is an installation issue (eg. incorrect .dll's). Help?

If am trying to use cairo and rsvg because they take up little space and are really fast; wand or some other library is not an option. I just want to be able to put an SVG file into a tkinter frame. If anyone knows how install rsvg properly, I'd appreciate knowing.

Any help would be hugely appreciated. Thank you for any suggestions.

Agraphia answered 1/5, 2019 at 22:45 Comment(8)
show your code.Haveman
Hi, the code I mainly used is present in the lase and 2nd last links.Agraphia
code in links work but your code not. So if you show code then we can search differences.Haveman
I added the code to the question. I think the errors are from how I installed cairo and rsvg rather than the code itself.Agraphia
I think that you should be able to use PIL.Image and PIL.ImageTk to do soModerato
@БогданОпир I can't figure out how to load a svg from the hard drive or internet with PIL. If you have any insights, I'd love to know.Agraphia
Take a look at pypi.org/project/svglib. In its example the svg is converted into png which allowes you to use PILModerato
Did you try renaming rsvg.py to something else?Effete
A
1

I have finally managed to convert SVGs with Python 3 and PyCairo on Windows, but without rsvg. Rsvg still won't cooperate, but apparently it is still possible to load SVGs without it.

The installation process is not very straightforward, but hey, it works!

 

Instructions:

Note that these instructions are Windows-specific. On Linux, one can simply install pycairo via pip and use PyGObject's rsvg.

  1. Download the pycairo .whl file for your Windows installation from https://www.lfd.uci.edu/~gohlke/pythonlibs/.
  2. Install the downloaded file via pip: pip install /path/to/your/pycairo/whl.whl If that doesn't work, try using a different file from the above link. It may take a few tries.
  3. Run pip install tinycss cssselect2 defusedxml. This will install the dependacies for the next step.
  4. Go to https://github.com/Kozea/CairoSVG. Download and extract the cairosvg folder to your site packages folder, enabling your code to import it.
  5. Go to the cairosvg folder and open the file surface.py.
  6. Look for the line that says import cairocffi as cairo and replace it with import cairo

That should be enough to use PyCairo on Windows without a C++ compiler. Unfortionately, this still doesn't fix the rsvg issues (instead it replaces rsvg), but at least it works.

 

Here are some examples of how to use it:

To convert an SVG to a PNG:

import cairosvg
cairosvg.svg2png(url="example.svg", write_to="output.png")

To put an SVG into a Tkinter window without downloading the output:

import cairosvg
import io
import tkinter as tk
from PIL import Image,ImageTk

main=tk.Tk()

image_data = cairosvg.svg2png(url="example.svg")
image = Image.open(io.BytesIO(image_data))
tk_image = ImageTk.PhotoImage(image)

button=tk.Label(main, image=tk_image)
button.pack(expand=True, fill="both")
main.mainloop()

 

Since it still uses Cairo, this solution is very quick, and has few dependencies.

Hopefully this answer will be useful for anyone reading this in the future!

Agraphia answered 15/12, 2020 at 0:45 Comment(0)
M
5

I've managed to do it using svglib:

from svglib.svglib import svg2rlg
from reportlab.graphics import renderPDF, renderPM

drawing = svg2rlg("safari-pinned-tab.f387b3f2.svg")
renderPM.drawToFile(drawing, "temp.png", fmt="PNG")


from tkinter import *

tk = Tk()


from PIL import Image, ImageTk

img = Image.open('temp.png')
pimg = ImageTk.PhotoImage(img)
size = img.size


frame = Canvas(tk, width=size[0], height=size[1])
frame.pack()
frame.create_image(0,0,anchor='nw',image=pimg)

tk.mainloop()

Moderato answered 31/3, 2020 at 13:33 Comment(1)
Thanks! The question was about rsvg, though. Any insights? Also, if it is possible to use svglib/reportlab without downloading the shape? Is it possible to somehow skip reportlab altogether?Agraphia
E
3

Credit to j_4321 for his answer here https://mcmap.net/q/742196/-how-to-open-svg-files-in-tkinter

I am just shining a slightly different light here in case it helps anyone.

From what I have been able to find, tksvg is the easiest and simplest way to visualise a SVG graphic in tkinter 8.6. I have been able to do the below in IDLE:

python -m pip install tksvg    ---> this is not in IDLE actually, but in cmd!

import tkinter as tk
import tksvg

window = tk.Tk()

d = '''<svg width="0" height="0"><path d="M17.2 26.6l1.4 2.9 3.2.5-2.2 2.3.6 3.2-2.9-1.5-2.9 1.5.6-3.2-2.3-2.3 3.2-.5zM44.8 3.8l2 .3-1.4 1.4.3 2-1.8-.9-1.8.9.3-2L41 4.1l2-.3.9-1.8zM8.9 10l.9 1.8 2 .3-1.4 1.4.3 2-1.8-.9-1.8.9.3-2L6 12.1l2-.3zm37.6 17l.647 1.424 1.553.258-1.165 1.165.26 1.553-1.424-.776-1.295.647.26-1.553-1.165-1.165 1.553-.259zM29.191 1C24.481 2.216 21 6.512 21 11.626c0 6.058 4.887 10.97 10.915 10.97 3.79 0 7.128-1.941 9.085-4.888-.87.224-1.783.344-2.724.344-6.028 0-10.915-4.912-10.915-10.97 0-2.25.674-4.341 1.83-6.082z" fill="#7694b4" fill-rule="evenodd"></path></svg>'''

# if you have a SVG file on disk, use the file parameter:
# svg_image = tksvg.SvgImage( file = 'path/to/file' )

# if you have SVG code from somewhere - in my case I scraped it from a website - use the data parameter:
svg_image = tksvg.SvgImage( data = d )

# You can also resize the image, but using only one of the three available parameters:
# svg_image = tksvg.SvgImage( data = d, scale = 0.5 )
# svg_image = tksvg.SvgImage( data = d, scaletowidth = 200 )
svg_image = tksvg.SvgImage( data = d, scaletoheight = 200 )

tk.Label( image = svg_image ).pack()

The final result is:

enter image description here

If you keep the SVG source code handy you can always resize the image by generating a new one.

Versioning: Windows 7x64, Python 3.8.10, tkinter 8.6.9.0, tksvg 0.7.4

Expulsion answered 15/10, 2023 at 22:28 Comment(2)
This is great, but incomplete. Last line should read tk.Label( window, ..., then add another line like window.mainloop()Kentigera
@Jann Poppinga - not really. If you omit the "window" argument then it just defaults to the main tkinter instance (which should always be one anyways). And because I ran this test in IDLE I didn't need to run .mainloop(). In a standalone application you will need the .mainloop(), yes. However, the main point here was how to visualise an SVG image...Expulsion
A
1

I have finally managed to convert SVGs with Python 3 and PyCairo on Windows, but without rsvg. Rsvg still won't cooperate, but apparently it is still possible to load SVGs without it.

The installation process is not very straightforward, but hey, it works!

 

Instructions:

Note that these instructions are Windows-specific. On Linux, one can simply install pycairo via pip and use PyGObject's rsvg.

  1. Download the pycairo .whl file for your Windows installation from https://www.lfd.uci.edu/~gohlke/pythonlibs/.
  2. Install the downloaded file via pip: pip install /path/to/your/pycairo/whl.whl If that doesn't work, try using a different file from the above link. It may take a few tries.
  3. Run pip install tinycss cssselect2 defusedxml. This will install the dependacies for the next step.
  4. Go to https://github.com/Kozea/CairoSVG. Download and extract the cairosvg folder to your site packages folder, enabling your code to import it.
  5. Go to the cairosvg folder and open the file surface.py.
  6. Look for the line that says import cairocffi as cairo and replace it with import cairo

That should be enough to use PyCairo on Windows without a C++ compiler. Unfortionately, this still doesn't fix the rsvg issues (instead it replaces rsvg), but at least it works.

 

Here are some examples of how to use it:

To convert an SVG to a PNG:

import cairosvg
cairosvg.svg2png(url="example.svg", write_to="output.png")

To put an SVG into a Tkinter window without downloading the output:

import cairosvg
import io
import tkinter as tk
from PIL import Image,ImageTk

main=tk.Tk()

image_data = cairosvg.svg2png(url="example.svg")
image = Image.open(io.BytesIO(image_data))
tk_image = ImageTk.PhotoImage(image)

button=tk.Label(main, image=tk_image)
button.pack(expand=True, fill="both")
main.mainloop()

 

Since it still uses Cairo, this solution is very quick, and has few dependencies.

Hopefully this answer will be useful for anyone reading this in the future!

Agraphia answered 15/12, 2020 at 0:45 Comment(0)
F
0

Here is another way to do it:

from pylunasvg import Document
import numpy as np
from urllib import request
from PIL import Image

contents = request.urlopen("https://betacssjs.chesscomfiles.com/bundles/web/favicons/safari-pinned-tab.f387b3f2.svg").read()

document = Document.loadFromData(contents)
bitmap = document.renderToBitmap()

svgArray = np.array(bitmap, copy=False)
img = Image.fromarray(svgArray)

# Insert tkinter code here

Disclaimer: I wrote the bindings for the library, here is the github link: pylunasvg and link to the original library written in c++: lunasvg

Fouts answered 7/10, 2021 at 20:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.