TkSVGslide 2.0 – Free App with svg files as slides

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
Avatar My youtube channel

Twitter: @pythonprogrammi - python_pygame

Videos

Speech recognition game

Pygame's Platform Game

Other Pygame's posts

Published by pythonprogramming

Started with basic on the spectrum, loved javascript in the 90ies and python in the 2000, now I am back with python, still making some javascript stuff when needed.