Here is a script allowing to display images in a resizable window, mantaining aspect ratio :
import tkinter as tk
from tkinter import ttk # For themed widgets (optional)
from PIL import Image, ImageTk
import os
class ImageApp:
def __init__(self, master, image_path):
self.master = master
master.title("C# Image Viewer")
self.image_path = image_path
self.original_image = None
self.tk_image = None
self.canvas_item = None # To hold the image on the canvas
# Check if image exists and load it
if not os.path.exists(self.image_path):
print(f"Error: Image file not found at {self.image_path}")
master.destroy() # Close the window if image not found
return
try:
self.original_image = Image.open(self.image_path)
print(f"Image successfully opened: {self.original_image.format}, {self.original_image.size}, {self.original_image.mode}")
except Exception as e:
print(f"Error loading image with Pillow: {e}")
master.destroy()
return
# Create a Canvas widget to display the image
self.canvas = tk.Canvas(master, bg="black", highlightthickness=0)
self.canvas.pack(fill=tk.BOTH, expand=True)
# Bind the <Configure> event to the resize_image method
# This event fires when the widget (canvas in this case) changes size
self.canvas.bind("<Configure>", self.resize_image)
# Initial display of the image
self.display_initial_image()
def display_initial_image(self):
if self.original_image:
# Get initial canvas size or set it to image size for first open
# This is a bit tricky as canvas size might be 1x1 initially.
# We'll rely on the <Configure> event to do the actual initial sizing.
# For the very first display, let's just make sure something is there.
# The <Configure> event will immediately follow and correctly size it.
temp_image = self.original_image.copy() # Avoid modifying original
# If the image is very large, you might want to scale it down for initial display
# otherwise, the window might open off-screen if the screen is too small.
# However, for maintaining aspect ratio, the resize_image method handles it.
self.tk_image = ImageTk.PhotoImage(temp_image)
self.canvas_item = self.canvas.create_image(0, 0, anchor=tk.NW, image=self.tk_image)
# Set initial window size to match image size (optional, can be skipped
# if you prefer the user to manually stretch to fit)
self.master.geometry(f"{self.original_image.width}x{self.original_image.height}")
def resize_image(self, event):
if self.original_image:
# Get current canvas dimensions
canvas_width = event.width
canvas_height = event.height
# Calculate aspect ratio
original_width, original_height = self.original_image.size
original_aspect_ratio = original_width / original_height
# Determine new dimensions to fit within canvas while maintaining aspect ratio
# Option 1: Fit by width (if new_height would be <= canvas_height)
new_width = canvas_width
new_height = int(new_width / original_aspect_ratio)
if new_height > canvas_height:
# Option 2: Fit by height (if Option 1 made image too tall)
new_height = canvas_height
new_width = int(new_height * original_aspect_ratio)
# Ensure minimum size to avoid errors with very small windows
if new_width <= 0 or new_height <= 0:
return # Do nothing if dimensions are invalid
# Resize the image using Pillow (Image.resize)
# Use Image.LANCZOS for high-quality downscaling/upscaling
resized_image = self.original_image.resize((new_width, new_height), Image.LANCZOS)
# Convert to PhotoImage for Tkinter
self.tk_image = ImageTk.PhotoImage(resized_image)
# Update the image on the canvas
# self.canvas_item = self.canvas.create_image(0, 0, anchor=tk.NW, image=self.tk_image)
# ^ This line creates new image objects; better to modify existing one
# Update the existing image object and center it
x_center = (canvas_width - new_width) // 2
y_center = (canvas_height - new_height) // 2
self.canvas.coords(self.canvas_item, x_center, y_center)
self.canvas.itemconfig(self.canvas_item, image=self.tk_image)
# --- Main execution ---
if __name__ == "__main__":
# IMPORTANT: Adjust this path to your image
image_file_path = r"C:\temp\cb\img.jpg"
root = tk.Tk()
app = ImageApp(root, image_file_path)
root.mainloop()