I made a new version of this app to present svg files (old version). Now the program does not use anymore a temp.png file on the drive, but a temporary file in the memory, so that it does not have to save it all the time the window is resized. Tkinter window, in fact, get a png file, so you need to convert svg to png and then get into tkinter with img = ImageTk.PhotoImage(im).
This code does also converts all the svg images into single pngs, if you want, and I’ve found that this is very helpful to use it with inkscape, because it takes me a little bit too long sometimes to save the svg files into png from within inkscape. So, now, I use this tool just to convert all the svg into png with one click.
In the previous version I used this:
def showimg(event): "takes the selected image to show it, called by root.bind <Configure> and lst.bind <<ListboxSelect>>" n = lst.curselection() filename = lst.get(n) drawing = svg2rlg(filename) renderPM.drawToFile(drawing, "temp.png", fmt="PNG") im = Image.open("temp.png") im = im.resize((get_window_size()), Image.ANTIALIAS) img = ImageTk.PhotoImage(im) w, h = img.width(), img.height() canvas.image = img canvas.config(width=w, height=h) canvas.create_image(0, 0, image=img, anchor=tk.NW) root.bind("<Configure>", lambda x: showimg(x)) root.title(filename)
Where I rendered the file to a png saved in the drive.
The new code
def showimg(event): "takes the selected image to show it, called by root.bind <Configure> and lst.bind <<ListboxSelect>>" n = lst.curselection() filename = lst.get(n) # Convertsvg drawing = svg2rlg(filename) # create a stream bytespng = BytesIO() # Save to BytesIO stream as png renderPM.drawToFile(drawing, bytespng, fmt="PNG") # Open and resize it like the window im = Image.open(bytespng) im = im.resize((get_window_size()), Image.ANTIALIAS) # transform fo tkinter img = ImageTk.PhotoImage(im) #img = img.resize((get_window_size(), Image.ANTIALIAS)) # get the width and height of the image w, h = img.width(), img.height() canvas.image = img # same size for the canvas canvas.config(width=w, height=h) # get the image with the new size in the canvas canvas.create_image(0, 0, image=img, anchor=tk.NW) # When change the window, redraw the canvas and image with the new size root.bind("<Configure>", lambda x: showimg(x)) root.title(filename)
Saves the svg file converted to png into the memory (not the drive) with BytesIO, then opens it with Image.open from PIL and resize it and then it gets it into tkinter with ImageTk.PhotoImage. Each time the window is resized, the root.bind listener calls again the function to redraw the canvas and image with the new size.
Video
The whole code
import tkinter as tk import glob from PIL import Image, ImageTk import os from svglib.svglib import svg2rlg from reportlab.graphics import renderPM from io import BytesIO def create_image(w,h, color): "Create an image in the memory" # create image img = Image.new("RGB", (w,h), color) # Saves the new image in memory, not on drive memfile = BytesIO() img.save(memfile, format="PNG") # do not need file argument, as it's an image in the memory img = tk.PhotoImage(memfile) return img def insertfiles(): "loads the list of files in the directory" for filename in glob.glob("*.svg"): lst.insert(tk.END, filename) def svgpng(): "Converts all svg in png" for filename in glob.glob("*.svg"): drawing = svg2rlg(filename) renderPM.drawToFile(drawing, filename[:-4] + ".png", fmt="PNG") def refresh(): lst.delete(0, tk.END) insertfiles() def delete_item(event): "Deletes a file in the list: called by lst.bind('<Control-d>', delete_item)" n = lst.curselection() os.remove(lst.get(n)) lst.delete(n) def get_window_size(): "Returns the width and height of the screen to set images and canvas alike it: called by root.bind <Configure>" if root.winfo_width() > 200 and root.winfo_height() >30: w = root.winfo_width() - 200 h = root.winfo_height() - 30 else: w = 200 h = 30 return w, h def showimg(event): "takes the selected image to show it, called by root.bind <Configure> and lst.bind <<ListboxSelect>>" n = lst.curselection() filename = lst.get(n) # Convertsvg drawing = svg2rlg(filename) # create a stream bytespng = BytesIO() # Save to BytesIO stream as png renderPM.drawToFile(drawing, bytespng, fmt="PNG") # Open and resize it like the window im = Image.open(bytespng) im = im.resize((get_window_size()), Image.ANTIALIAS) # transform fo tkinter img = ImageTk.PhotoImage(im) #img = img.resize((get_window_size(), Image.ANTIALIAS)) # get the width and height of the image w, h = img.width(), img.height() canvas.image = img # same size for the canvas canvas.config(width=w, height=h) # get the image with the new size in the canvas canvas.create_image(0, 0, image=img, anchor=tk.NW) # When change the window, redraw the canvas and image with the new size root.bind("<Configure>", lambda x: showimg(x)) root.title(filename) root = tk.Tk() root.geometry("800x600+300+50") old_width, old_height = get_window_size() lst = tk.Listbox(root, width=20) lst.pack(side="left", fill=tk.BOTH, expand=0) lst.bind("<<ListboxSelect>>", showimg) lst.bind("<Control-d>", delete_item) insertfiles() canvas = tk.Canvas(root) canvas.pack() menu = tk.Menu() menu.add_command(label="Refresh", command=refresh) menu.add_command(label="svg-png", command=svgpng) root.configure(menu=menu) root.mainloop()
Subscribe to the newsletter for updates
Tkinter templates
My youtube channel
Twitter: @pythonprogrammi - python_pygame