#!/usr/bin/env python3 import tkinter as tk from PIL import Image, ImageTk import screeninfo, sys, os def show_image(image_path, max_width=400, max_height=300, hover_header=None, click_url=None): root = tk.Tk() root.overrideredirect(True) root.withdraw() root.after(100, root.deiconify) root.attributes("-topmost", True) root.attributes("-alpha", 0.85) img = Image.open(image_path) img_ratio = img.width / img.height box_ratio = max_width / max_height if img.width > max_width or img.height > max_height: if img_ratio > box_ratio: new_width = max_width new_height = int(max_width / img_ratio) else: new_height = max_height new_width = int(max_height * img_ratio) try: resample = Image.Resampling.LANCZOS except AttributeError: resample = Image.ANTIALIAS img = img.resize((new_width, new_height), resample) img_tk = ImageTk.PhotoImage(img) img_width, img_height = img.size monitors = screeninfo.get_monitors() primary_screen = next((m for m in monitors if m.is_primary), monitors[0]) screen_x = primary_screen.x screen_y = primary_screen.y screen_width = primary_screen.width screen_height = primary_screen.height x_pos = screen_x + screen_width - img_width - 20 y_pos = screen_y + screen_height - img_height - 60 root.geometry(f"{img_width}x{img_height}+{x_pos}+{y_pos}") label = tk.Label(root, image=img_tk, borderwidth=0) label.image = img_tk label.pack() header_label = tk.Label(root, text=hover_header, bg="black", fg="white", font=("Arial", 10)) header_visible = [False] def update_hover_state(): x, y = root.winfo_pointerx() - root.winfo_rootx(), root.winfo_pointery() - root.winfo_rooty() inside_label = 0 <= x <= img_width and 0 <= y <= img_height inside_header = header_label.winfo_ismapped() and header_label.winfo_containing(x + root.winfo_rootx(), y + root.winfo_rooty()) is not None if hover_header and (inside_label or inside_header): if not header_visible[0]: header_label.place(relx=0.5, rely=0, anchor="n", relwidth=1) header_visible[0] = True else: if header_visible[0]: header_label.place_forget() header_visible[0] = False root.after(100, update_hover_state) def close_window(event=None): root.destroy() root.bind("", close_window if click_url is None else lambda e: os.system(f"xdg-open {click_url}")) update_hover_state() root.after(5000, close_window) root.mainloop() if __name__ == "__main__": if len(sys.argv) < 2: print("Usage: show_image.py [hover_header] [click_url]") sys.exit(1) image_path = sys.argv[1] hover_header = sys.argv[2] if len(sys.argv) > 2 else None click_url = sys.argv[3] if len(sys.argv) > 3 else None show_image(image_path, hover_header=hover_header, click_url=click_url)