将 .SVG 图像放入 tkinter 框架中。

17

我一直在尝试将来自https://betacssjs.chesscomfiles.com/bundles/web/favicons/safari-pinned-tab.f387b3f2.svg的图像放入Tkinter框架中。 我从这里的帖子中发现,可以通过rsvg和cairo的帮助实现。

我使用的是Windows 10上的Python 3.6。我从这里获取了rsvg,从这里获取了cairo,然后将文件夹提取到'C:\ Users ... \ site_packages'文件夹中。它们可以很好地导入,但我不知道如何使用它们。我尝试使用以下代码:

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)

#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)
尝试了这些脚本后,我一直收到错误信息:

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

我相信在过程中我做错了什么,但是经过几个小时的搜索,仍然无法弄清楚如何让它工作。我还尝试通过pip安装pycairo,但是收到了错误消息。

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\

我现在完全不知道该怎么做了。

编辑:我最终从这里获取到了pycairo,并且现在让它工作正常了。 我通过参考这里,并从这里获取所需的DLL文件,终于使得rsvg不再给我上面的错误信息。 Cairo工作正常,但RSVG创建了一个空白屏幕。我尝试了另一个7行代码的方法here,输出的是一个空白文件而不是转换后的文件。显然,RSVG不起作用,我认为这是安装问题(例如,不正确的.dll文件)。 求助?

我正在尝试使用cairo和rsvg,因为它们占用很少的空间,并且非常快速;wand或其他库不是选项。我只想能够将SVG文件放入tkinter框架中。如果有人知道如何正确安装rsvg,我会很感激知道。

任何帮助都将不胜感激。 感谢任何建议。


4
展示你的代码。 - furas
3
嗨,我主要使用的代码在倒数第二个和最后一个链接中。 - Andereoo
2
链接中的代码可以工作,但是你的代码不行。因此,如果你展示代码,我们就可以搜索差异。 - furas
我认为你应该能够使用PIL.Image和PIL.ImageTk来实现。 - rizerphe
@БогданОпир 我无法弄清楚如何使用PIL从硬盘或互联网加载svg。如果您有任何见解,我很想知道。 - Andereoo
显示剩余3条评论
4个回答

5

我使用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()


1
谢谢!问题是关于rsvg的,有什么见解吗?此外,是否可以在不下载形状的情况下使用svglib/reportlab?是否可能完全跳过reportlab? - Andereoo

1
我终于成功地在Windows上使用Python 3和PyCairo转换了SVG,但没有使用rsvg。Rsvg仍然不合作,但显然仍然可以在没有它的情况下加载SVG。
安装过程并不是很直观,但嘿,它能用!

 

说明:

请注意这些说明适用于Windows。在Linux上,可以通过pip安装pycairo并使用PyGObject的rsvg。

  1. https://www.lfd.uci.edu/~gohlke/pythonlibs/下载适用于您的Windows版本的pycairo .whl文件。
  2. 通过pip安装已下载的文件:pip install /path/to/your/pycairo/whl.whl 如果无法安装,请尝试使用上述链接中的其他文件。可能需要尝试几次。
  3. 运行pip install tinycss cssselect2 defusedxml。这将安装下一步所需的依赖项。
  4. 进入https://github.com/Kozea/CairoSVG。下载并提取cairosvg文件夹到您的站点包文件夹,使您的代码可以导入它。
  5. 进入cairosvg文件夹并打开surface.py文件。
  6. 查找其中一行代码:import cairocffi as cairo并替换为import cairo

这应该足以在Windows上使用PyCairo,而无需C++编译器。不幸的是,这仍然不能解决rsvg问题(而是替换了rsvg),但至少能够正常工作。

 

这里有一些使用它的示例:
将SVG转换为PNG:

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

将SVG放入Tkinter窗口中而无需下载输出:
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()

 

由于它仍然使用Cairo,所以这个解决方案非常快速,并且依赖很少。

希望这个答案对未来任何阅读此内容的人有用!


0

这里有另一种方法:

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

声明:我编写了该库的绑定,这是github链接:pylunasvg,原始c++库的链接为:lunasvg


0
感谢j_4321在这里提供的答案https://dev59.com/7r7pa4cB1Zd3GeqPsiny#64829808
我只是在这里稍微以不同的角度来帮助任何人。
根据我所了解,tksvg是在tkinter 8.6中可视化SVG图形的最简单和最简洁的方法。我已经在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()

最终结果是:

enter image description here

如果你保留SVG源代码,你可以随时通过生成新的代码来调整图像的大小。
版本信息:Windows 7x64,Python 3.8.10,tkinter 8.6.9.0,tksvg 0.7.4。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接