#!/usr/bin/env python3 # File: sample.py # License: CC-BY-SA 4.0 # Author: bgstack15 # Startdate: 2019-06-14 17:42 # Title: Learning how to display an svg in tcl/tk with python # Purpose: # History: # Usage: # References: # rsvg https://stackoverflow.com/questions/10393675/rsvg-with-python-3-2-on-ubuntu/19744099#19744099 # svg for tkinter http://code.activestate.com/lists/python-list/595078/ # Improve: # add svg support # Dependencies: # package: RPM | DPKG # tkinter: python36-tkinter | python3-tk # PIL: python36-pillow-tk | python3-pil.imagetk # cairo: python36-cairo | python3-cairo # Rsvg: python36-gobject | gir1.2-rsvg-3.0 import os, sys, configparser, glob, re, cairo import tkinter as tk import tkinter.ttk as ttk from functools import partial from pathlib import Path from PIL import Image, ImageTk sys.path.append("/home/bgirton/dev/logout-manager") import lmlib import inspect # here for troubleshooting sample.py only WITH_SVG=True if not WITH_SVG is None and WITH_SVG: from gi import require_version require_version('Rsvg', '2.0') from gi.repository import Rsvg as rsvg #if TkVersion < 8.6: # USE_PRIVATE_TCL_IMAGES = 1 # print("Loading private PIL translation layter") # def PhotoImage_from_png(file): # return ImageTk.PhotoImage(file=file) config = lmlib.Initialize_config() actions = lmlib.Actions # graphical classes and functions print("Loading graphics...") 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 = int((((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(str(bgra_buffer[idx + 2])), ord(str(bgra_buffer[idx + 1])), ord(str(bgra_buffer[idx + 0])), ord(str(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"]))]) #print(template) #print(arguments[-1]) 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() svg.new_from_file(file_name=file_path_name) #print(svg) #print(inspect.getmembers(rsvg.Handle)) #svg.open(file=file_path_name) #print(svg.height) #print(svg.get_dimensions().height) #print(inspect.getmembers(rsvg.DimensionData)) #width, height = svg.get_dimensions()[:2] width, height = [48,48] surface = cairo.ImageSurface(cairo.FORMAT_RGB24, int(width), int(height)) context = cairo.Context(surface) svg.render_cairo(context) image = tk.PhotoImage(width=width, height=height) data = convert(surface.get_data(), width, height) image.put(data) return(image) def get_scaled_icon(icon_name, size = 24, icon_theme = "default", fallback_icon_name = ""): iconfilename = None # assume icon_name is file. iconfilename = icon_name # So now that we think we have derived the correct filename... photo = photoimage_from_svg(iconfilename) #try: # print("Trying svg file",iconfilename) # # try an svg # if re.compile(".*\.svg").match(iconfilename): # print("Trying svg...") # photo = photoimage_from_svg(iconfilename) #except Exception as e: # print("Error with icon file:",e) # if "gobject" in str(e): # raise # return None photo.thumbnail(size=[size, size]) try: photo2 = ImageTk.PhotoImage(photo) except Exception as e: print("Error was ",e) return photo2 class App: def __init__(self, master): frame = tk.Frame(master) frame.grid(row=0) self.buttonLock = tk.Button(frame, text="Lock", underline=3, command=partial(actions.lock,config)) self.buttonLock.grid(row=0,column=0) # WORKS master.bind_all("", something) # PASSES 2 params when expecting 1 master.bind_all("", self.buttonLock.invoke) master.bind_all("", partial(actions.lock,config)) # WORKS, for basic image loading. self.photoLogout = get_scaled_icon(config.get_logout_icon(), config.get_icon_size(), config.get_icon_theme()) self.buttonLogout = tk.Button(frame, text="Logout", underline=0, command=lambda: actions.logout(config), image=self.photoLogout, compound=tk.LEFT) master.bind_all("", partial(actions.logout,config)) Tooltip(self.buttonLogout, text="HERE IS SOMETHING!") self.buttonLogout.grid(row=0,column=1) #self.buttonCancel = tk.Button(frame, text="Cancel", underline=0, command=frame.quit) self.buttonCancel = tk.Button(frame, text="Cancel", underline=0, command=self.quitaction) self.buttonCancel.grid(row=1,columnspan=8,sticky=tk.W+tk.E) master.bind_all("", self.quitaction) # Found this after trial and error. def quitaction(self,b=None): print("Cancel any logout action.") root.destroy() # Left here as an example for a mster.bind_all that works. #def something(event=None): # print("Got here!") root = tk.Tk() # MAIN LOOP root.title("Log out options") imgicon = get_scaled_icon("/usr/share/icons/Numix/96/actions/system-shutdown.svg",24) print(imgicon) root.tk.call('wm','iconphoto', root._w, imgicon) app = App(root) root.mainloop() try: root.destroy() except: pass