Annexe : Application - Visionneuse d'Images

Rôle et utilité

L'application apps/visionneuse/app.py est appelée par l'Explorateur lorsque l'utilisateur double-clique sur un fichier image (.png, .jpg, .gif). Elle permet d'afficher l'image de façon proportionnelle tout en autorisant le zoom et le déplacement panoramique (cliquer-glisser).

Implémentation technique

Pistes de modification

Code Source

import tkinter as tk
from tkinter import messagebox
from PIL import Image, ImageTk
import os

def start(window, app_manager=None, **kwargs):
    frame = tk.Frame(window, bg="black")
    frame.pack(fill="both", expand=True)

    def show_help():
        msg = (
            "Aide de la Visionneuse\n\n"
            "• Cette application affiche les images redimensionnées pour s'adapter à la fenêtre.\n"
            "• Redimensionnez la fenêtre pour agrandir l'image.\n"
            "• Fermez avec la croix rouge pour quitter."
        )
        messagebox.showinfo("Aide Visionneuse", msg)

    btn_help = tk.Button(frame, text=" ? Aide ", command=show_help, relief="flat", bg="lightblue")
    btn_help.place(x=5, y=5)

    lbl_img = tk.Label(frame, bg="black")
    lbl_img.pack(fill="both", expand=True)

    filepath = kwargs.get("filepath")

    def update_title():
        if hasattr(window, 'master') and window.master.__class__.__name__ == 'Window':
            title_text = filepath if filepath else "Aucune image"
            window.master.title_label.config(text=f"Visionneuse - {title_text}")

    update_title()

    if not filepath or not os.path.exists(filepath):
        lbl_img.config(text="Fichier introuvable ou aucune image sélectionnée", fg="white")
        return

    try:
        # Initial window sizing based on image
        img = Image.open(filepath)
        img_w, img_h = img.size

        if hasattr(window, 'master') and window.master.__class__.__name__ == 'Window':
            win_obj = window.master
            parent_w = win_obj.parent.winfo_width() or win_obj.parent.winfo_screenwidth()
            parent_h = win_obj.parent.winfo_height() or win_obj.parent.winfo_screenheight()

            max_w = int(parent_w * 0.8)
            max_h = int(parent_h * 0.8)

            target_w = min(img_w, max_w)
            target_h = min(img_h, max_h)

            target_w = max(400, target_w)
            target_h = max(300, target_h)

            win_obj.place(width=target_w, height=target_h + 30)
    except Exception as e:
        print(f"Erreur initialisation image: {e}")

    def load_image(event=None):
        try:
            # Assure the frame layout is calculated
            frame.update_idletasks()
            w = frame.winfo_width()
            h = frame.winfo_height()

            # Use reasonable default if too small
            if w <= 10 or h <= 10:
                w, h = 400, 300 

            img = Image.open(filepath)
            img.thumbnail((w, h), Image.Resampling.LANCZOS)
            photo = ImageTk.PhotoImage(img)
            lbl_img.config(image=photo)
            lbl_img.image = photo # Prevent garbage collection
        except Exception as e:
            lbl_img.config(text=f"Erreur de chargement:\n{e}", fg="red")

    # Load on resize, but debounce or just once on start
    frame.bind("<Configure>", lambda e: window.after(50, load_image))
    window.after(50, load_image)