generated from brennen/python_project
use PIL for image handling
This commit is contained in:
@@ -1,33 +1,40 @@
|
|||||||
import mimetypes
|
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
from collections import namedtuple
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
import tkinter as tk
|
from tkinter import *
|
||||||
import tkinter.messagebox as messagebox
|
import tkinter.messagebox as messagebox
|
||||||
import tkinter.filedialog as filedialog
|
import tkinter.filedialog as filedialog
|
||||||
import tkinter.ttk as ttk
|
from tkinter.ttk import *
|
||||||
|
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from platform import system
|
from platform import system
|
||||||
|
|
||||||
|
from PIL import ImageOps
|
||||||
|
from PIL.ImageTk import Image, PhotoImage
|
||||||
from serial import Serial
|
from serial import Serial
|
||||||
|
|
||||||
if not mimetypes.inited:
|
Resolution = namedtuple("Resolution", ("height", "width"))
|
||||||
mimetypes.init()
|
IWII_RESOLUTION = Resolution(576, 720)
|
||||||
|
|
||||||
|
SUPPORTED_IMAGE_TYPES = sorted("*"+ext for ext, type_ in Image.registered_extensions().items() if type_ in ("PNG", "GIF", "JPEG", "WEBP", "BMP"))
|
||||||
|
|
||||||
def handle_action_exceptions(func: Callable):
|
def widget_action(func: Callable):
|
||||||
|
# decorator to wrap widget actions in an error handler that displays exceptions in error message windows
|
||||||
@wraps(func)
|
@wraps(func)
|
||||||
def wrapper(event: tk.Event):
|
def wrapper(event: Event):
|
||||||
try:
|
try:
|
||||||
func(event)
|
func(event)
|
||||||
except NotImplementedError as e:
|
except NotImplementedError as e:
|
||||||
messagebox.showwarning(
|
messagebox.showwarning(
|
||||||
title="Warning",
|
title="Warning",
|
||||||
message=f"{func.__name__} Not Implemented",
|
message=f"{func.__name__} not implemented",
|
||||||
parent=event.widget.master
|
parent=event.widget.master
|
||||||
)
|
)
|
||||||
|
except SystemExit:
|
||||||
|
# probably unnecessary, but we don't want to accidentally intercept requests to exit
|
||||||
|
raise
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
messagebox.showerror(
|
messagebox.showerror(
|
||||||
title="Error",
|
title="Error",
|
||||||
@@ -41,51 +48,66 @@ def handle_action_exceptions(func: Callable):
|
|||||||
return wrapper
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
@handle_action_exceptions
|
@widget_action
|
||||||
def open_preview(event: tk.Event):
|
def open_preview(event: Event):
|
||||||
file = filedialog.askopenfilename(
|
file = filedialog.askopenfilename(
|
||||||
parent=event.widget.master,
|
parent=event.widget.master,
|
||||||
title="Open Image",
|
title="Open Image",
|
||||||
initialdir=Path.home(),
|
initialdir=Path.home(),
|
||||||
filetypes=[
|
filetypes=[
|
||||||
(mimetype, "*"+ext) for ext, mimetype in mimetypes.types_map.items()
|
("Supported Image Files", " ".join(SUPPORTED_IMAGE_TYPES))
|
||||||
if ext in (".png",".gif", ".pgm", ".ppm")
|
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
|
|
||||||
if Path(file).exists():
|
if not file:
|
||||||
# don't GC the photo when this function exits
|
return
|
||||||
global _photo
|
elif Path(file).exists() and Path(file).is_file():
|
||||||
_photo=tk.PhotoImage(file=file)
|
# load image data and resize to fit the IWII resolution preserving aspect ratio
|
||||||
event.widget.create_image(0,0, anchor=tk.NW, image=_photo)
|
image_data = ImageOps.contain(Image.open(file), IWII_RESOLUTION)
|
||||||
|
photo = PhotoImage(image_data, size=IWII_RESOLUTION)
|
||||||
|
event.widget.create_image(0,0, anchor=NW, image=photo)
|
||||||
|
# tkinter does not maintain a reference to the local variables of this function upon return
|
||||||
|
# without references, the photo and its data get garbage collected and nothing is display
|
||||||
|
# therefore we must create references to them to keep them around
|
||||||
|
event.widget._displayed_photo=photo
|
||||||
|
event.widget.master.photobooth_image = image_data
|
||||||
|
|
||||||
@handle_action_exceptions
|
@widget_action
|
||||||
def send_to_iwii(event: tk.Event):
|
def send_to_iwii(event: Event):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
def photobooth():
|
def photobooth():
|
||||||
app = tk.Tk()
|
app = Tk()
|
||||||
|
app.photobooth_image = None
|
||||||
app.title("PhotoBooth")
|
app.title("PhotoBooth")
|
||||||
style = ttk.Style()
|
|
||||||
|
style = Style()
|
||||||
|
|
||||||
match system():
|
match system():
|
||||||
case "Windows":
|
case "Windows":
|
||||||
try:
|
try:
|
||||||
style.theme_use("winnative")
|
style.theme_use("winnative")
|
||||||
except tk.TclError:
|
except TclError:
|
||||||
style.theme_use("vista")
|
style.theme_use("vista")
|
||||||
case "Darwin":
|
case "Darwin":
|
||||||
style.theme_use("aqua")
|
style.theme_use("aqua")
|
||||||
case "Linux":
|
case "Linux":
|
||||||
style.theme_use("alt")
|
style.theme_use("alt")
|
||||||
|
# https://python-forum.io/thread-31235.html
|
||||||
|
try:
|
||||||
|
# this is so stupid! you have to intentionally do this just to initialize the
|
||||||
|
# required namespace to set variables to hide hidden files by default
|
||||||
|
app.tk.call("tk_getOpenFile", "-intentionalnonsense")
|
||||||
|
except TclError:
|
||||||
|
app.setvar("::tk::dialog::file::showHiddenBtn", 1)
|
||||||
|
app.setvar("::tk::dialog::file::showHiddenVar", 0)
|
||||||
case _:
|
case _:
|
||||||
style.theme_use("default")
|
style.theme_use("default")
|
||||||
|
|
||||||
preview = tk.Canvas(master=app, height=576, width=720)
|
preview = Canvas(master=app, height=IWII_RESOLUTION.height, width=IWII_RESOLUTION.width)
|
||||||
preview.bind("<space>", open_preview)
|
preview.bind("<space>", open_preview)
|
||||||
preview.bind("<return>", send_to_iwii)
|
preview.bind("<Return>", send_to_iwii)
|
||||||
preview.focus_set()
|
preview.focus_set()
|
||||||
preview.pack(side="top")
|
preview.pack(side="top")
|
||||||
app.mainloop()
|
app.mainloop()
|
||||||
|
|||||||
Reference in New Issue
Block a user