jack.py
jack.py

Reputation: 442

Dynamically resize images in Tkinter

I have several images that I need to display in a Tkinter window (I'll probably use a canvas to display them - possibly a label). These images will take up about a third of the screen. I need the image-screen ratio to be consistent when the user uses different sized monitors.

So say the user uses a tiny monitor, the images need to take up the same photo-screen ration on the small screen, to when the user uses a massive 4K monitor.

Will Tkinter automatically do this for me? Or will I have to implement it myself - if so, is that even possible?

I don't have any code because I have no idea where to start. I thought that I could use PIL or pillow maybe, but I'm fairly new to them.

Any help would be appreciated, thanks :)

Upvotes: 1

Views: 4426

Answers (2)

JADem
JADem

Reputation: 1

Yes, you can do it like this:

import PIL.Image
import tkinter as tk
from PIL import ImageTk
from tkinter.filedialog import askopenfilename

class CanvasImage(tk.Canvas):
    def __init__(self, master: tk.Tk, **kwargs):
        super().__init__(master, **kwargs)

        self.source_image = None
        self.image_id = None
        self.image = None

        self.width, self.height = 0, 0
        self.center_x, self.center_y = 0, 0
        self.bind('<Configure>', self.update_values)
    
    def update_values(self, *_) -> None:
        self.width = self.winfo_width()
        self.height = self.winfo_height()
        self.center_x = self.width//2
        self.center_y = self.height//2

        if self.image is None: return
        self.delete_previous_image()
        self.resize_image()
        self.paste_image()

    def delete_previous_image(self) -> None:
        if self.image is None: return
        self.delete(self.image_id)
        self.image = self.image_id = None

    def resize_image(self) -> None:
        image_width, image_height = self.source_image.size
        width_ratio = self.width / image_width
        height_ratio = self.height / image_height
        ratio = min(width_ratio, height_ratio)

        new_width = int(image_width * ratio)
        new_height = int(image_height * ratio)
        scaled_image = self.source_image.resize((new_width, new_height))
        self.image = ImageTk.PhotoImage(scaled_image)

    def paste_image(self) -> None:
        self.image_id = self.create_image(self.center_x, self.center_y, image=self.image)

    def open_image(self) -> None:
        if not (filename := askopenfilename()): return

        self.delete_previous_image()
        self.source_image = PIL.Image.open(filename)
        self.image = ImageTk.PhotoImage(self.source_image)

        self.resize_image()
        self.paste_image()


class Window(tk.Tk):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.canvas = CanvasImage(self, relief='sunken', bd=2)
        tk.Button(self, text='Abrir imagen', comman=self.canvas.open_image).pack()
        self.canvas.pack(expand=True, fill='both', padx=10, pady=10)


if __name__ == '__main__':
    window = Window()
    window.mainloop()

Upvotes: 0

Maciek
Maciek

Reputation: 612

1) You need to get current screen resolution: How do I get monitor resolution in Python?
2) Then you need to adjust size of your image (How do I resize an image using PIL and maintain its aspect ratio?) and/or your window (https://yagisanatode.com/2018/02/23/how-do-i-change-the-size-and-position-of-the-main-window-in-tkinter-and-python-3/)

So the code should look like that:

from win32api import GetSystemMetrics
from Tkinter import Tk

screen_width, screen_height = GetSystemMetrics(0), GetSystemMetrics(1)

root = Tk() # this is your window
root.geometry("{}x{}".format(screen_width//2, screen_height//2)) # set size of you window here is example for 1/2 screen height and width

img = Image.open("picture_name.png", "r") # replace with picture path
width, height = screen_width//4, screen_height//4 # determine widght and height basing on screen_width, screen_height
img.resize((width, height), Image.ANTIALIAS) 

# todo: create more Tkinter objects and pack them into root

root.mainloop()

This should probably solve your problem. Regarding Tkinter usage, there are a lot of tutorials, example: http://effbot.org/tkinterbook/

Upvotes: 1

Related Questions