Allow window resizing when in single photo mode. Updated the PIL resizing to much more recent resizing code.

This commit is contained in:
PySimpleGUI 2023-08-10 12:44:33 -04:00
parent 5035d24f2c
commit 854bdccdd3
1 changed files with 123 additions and 37 deletions

View File

@ -1,8 +1,12 @@
import PySimpleGUI as sg
import datetime
import PIL.Image, PIL.ImageTk
import PIL
from PIL import Image
import random
import os
import io
import base64
"""
Another simple Desktop Widget using PySimpleGUI
@ -16,17 +20,76 @@ import os
* How long to show the image and if you wnt this time to vary semi-randomly
* Folder containing your images
Copyright 2021 PySimpleGUI
Copyright 2021, 2023 PySimpleGUI
"""
ALPHA = 0.9 # Initial alpha until user changes
refresh_font = sg.user_settings_get_entry('-refresh font-', 'Courier 8')
def convert_to_bytes(file_or_bytes, resize=None):
image = PIL.Image.open(file_or_bytes)
image.thumbnail(resize)
photo_img = PIL.ImageTk.PhotoImage(image)
return photo_img
def make_square(im, fill_color=(0, 0, 0, 0)):
x, y = im.size
size = max(x, y)
new_im = Image.new('RGBA', (size, size), fill_color)
new_im.paste(im, (int((size - x) / 2), int((size - y) / 2)))
return new_im
def get_image_size(source):
if isinstance(source, str):
image = PIL.Image.open(source)
elif isinstance(source, bytes):
image = PIL.Image.open(io.BytesIO(base64.b64decode(source)))
else:
image = PIL.Image.open(io.BytesIO(source))
width, height = image.size
return (width, height)
def convert_to_bytes(source, size=(None, None), subsample=None, zoom=None, fill=False):
"""
Will convert into bytes and optionally resize an image that is a file or a base64 bytes object.
Turns into PNG format in the process so that can be displayed by tkinter
:param source: either a string filename or a bytes base64 image object
:type source: (Union[str, bytes])
:param size: optional new size (width, height)
:type size: (Tuple[int, int] or None)
:param subsample: change the size by multiplying width and height by 1/subsample
:type subsample: (int)
:param zoom: change the size by multiplying width and height by zoom
:type zoom: (int)
:param fill: If True then the image is filled/padded so that the image is square
:type fill: (bool)
:return: (bytes) a byte-string object
:rtype: (bytes)
"""
# print(f'converting {source} {size}')
if isinstance(source, str):
image = PIL.Image.open(source)
elif isinstance(source, bytes):
image = PIL.Image.open(io.BytesIO(base64.b64decode(source)))
else:
image = PIL.Image.open(io.BytesIO(source))
width, height = image.size
scale = None
if size != (None, None):
new_width, new_height = size
scale = min(new_height/height, new_width/width)
elif subsample is not None:
scale = 1/subsample
elif zoom is not None:
scale = zoom
resized_image = image.resize((int(width * scale), int(height * scale)), Image.ANTIALIAS) if scale is not None else image
if fill and scale is not None:
resized_image = make_square(resized_image)
# encode a PNG formatted version of image into BASE64
with io.BytesIO() as bio:
resized_image.save(bio, format="PNG")
contents = bio.getvalue()
encoded = base64.b64encode(contents)
return encoded
def choose_theme(location):
@ -43,6 +106,15 @@ def choose_theme(location):
else:
return None
def reset_settings():
sg.user_settings_set_entry('-time per image-', 60)
sg.user_settings_set_entry('-random time-', False)
sg.user_settings_set_entry('-image size-', (None, None))
sg.user_settings_set_entry('-image_folder-', None)
sg.user_settings_set_entry('-location-', (None, None))
sg.user_settings_set_entry('-single image-', None)
sg.user_settings_set_entry('-alpha-', ALPHA)
def make_window(location):
alpha = sg.user_settings_get_entry('-alpha-', ALPHA)
@ -61,7 +133,7 @@ def make_window(location):
layout = [[sg.Image(k='-IMAGE-', enable_events=True)],
[sg.pin(sg.Column(refresh_info, key='-REFRESH INFO-', element_justification='c', visible=sg.user_settings_get_entry('-show refresh-', True)))]]
window = sg.Window('Photo Frame', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_justification='c', element_padding=(0, 0), alpha_channel=alpha, finalize=True, right_click_menu=right_click_menu, keep_on_top=True, enable_close_attempted_event=True)
window = sg.Window('Photo Frame', layout, location=location, no_titlebar=True, grab_anywhere=True, margins=(0, 0), element_justification='c', element_padding=(0, 0), alpha_channel=alpha, finalize=True, right_click_menu=right_click_menu, keep_on_top=True, enable_close_attempted_event=True, enable_window_config_events=True)
return window
@ -69,11 +141,10 @@ def make_window(location):
def main():
loc = sg.user_settings_get_entry('-location-', (None, None))
sg.theme(sg.user_settings_get_entry('-theme-', None))
window = make_window(loc)
time_per_image = sg.user_settings_get_entry('-time per image-', 60)
vary_randomly = sg.user_settings_get_entry('-random time-', False)
width, height = sg.user_settings_get_entry('-image size-', (400,300))
width, height = sg.user_settings_get_entry('-image size-', (None, None))
image_folder = sg.user_settings_get_entry('-image_folder-', None)
try:
@ -82,36 +153,26 @@ def main():
image_folder = None
sg.user_settings_set_entry('-image_folder-', None)
single_image = sg.user_settings_get_entry('-single image-', None)
image_name = single_image = sg.user_settings_get_entry('-single image-', None)
if image_folder is None and single_image is None:
while True:
images = None
image_folder = sg.popup_get_folder('Choose location of your images', location=window.current_location(), keep_on_top=True)
if image_folder is not None:
sg.user_settings_set_entry('-image_folder-', image_folder)
break
else:
if sg.popup_yes_no('No folder entered','Go you want to exit the program entirely?', keep_on_top=True) == 'Yes':
exit()
elif single_image is None:
image_name = single_image = sg.popup_get_file('Choose a starting image', keep_on_top=True)
if not single_image:
if sg.popup_yes_no('No folder entered','Go you want to exit the program entirely?', keep_on_top=True) == 'Yes':
exit()
if image_folder is not None and single_image is None:
images = os.listdir(image_folder)
images = [i for i in images if i.lower().endswith(('.png', '.jpg', '.gif'))]
image_name = os.path.join(image_folder, random.choice(images))
else: # means single image is not none
images = None
image_name = single_image
window = make_window(loc)
window_size = window.size
image_data = convert_to_bytes(image_name, (width, height))
while True: # Event Loop
# First update the status information
# for debugging show the last update date time
if single_image is None:
image_name =random.choice(images)
image_data = convert_to_bytes(os.path.join(image_folder, image_name), (width, height))
window['-FOLDER-'].update(image_folder)
else:
image_name = single_image
image_data = convert_to_bytes(single_image, (width, height))
window['-FILENAME-'].update(image_name)
window['-IMAGE-'].update(data=image_data)
window['-REFRESHED-'].update(datetime.datetime.now().strftime("%m/%d/%Y %I:%M:%S %p"))
# -------------- Start of normal event loop --------------
timeout = time_per_image * 1000 + (random.randint(int(-time_per_image * 500), int(time_per_image * 500)) if vary_randomly else 0) if single_image is None else None
event, values = window.read(timeout=timeout)
@ -120,6 +181,28 @@ def main():
elif event in (sg.WIN_CLOSE_ATTEMPTED_EVENT, 'Exit'):
sg.user_settings_set_entry('-location-', window.current_location()) # The line of code to save the position before exiting
break
# First update the status information
# for debugging show the last update date time
if event == sg.TIMEOUT_EVENT:
if single_image is None:
image_name =random.choice(images)
image_data = convert_to_bytes(os.path.join(image_folder, image_name))
window['-FOLDER-'].update(image_folder)
else:
image_name = single_image
image_data = convert_to_bytes(single_image, (width, height))
window['-FILENAME-'].update(image_name)
window['-IMAGE-'].update(data=image_data)
window['-REFRESHED-'].update(datetime.datetime.now().strftime("%m/%d/%Y %I:%M:%S %p"))
if event == sg.WINDOW_CONFIG_EVENT:
new_size = window.size
if new_size != window_size:
print(f'resizing {new_size}')
(width, height) = new_size
image_data = convert_to_bytes(image_data, (width, height))
window['-IMAGE-'].update(data=image_data)
window.size = get_image_size(image_data)
window_size = window.size
if event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'Choose Image Folder':
@ -175,12 +258,15 @@ def main():
window.close()
window = make_window(loc)
elif event == 'Choose Single Image':
single_image = sg.popup_get_file('Choose single image to show', history=True)
image_name = single_image = sg.popup_get_file('Choose single image to show', history=True)
sg.user_settings_set_entry('-single image-', single_image)
(width, height) = get_image_size(single_image)
sg.user_settings_set_entry('-image size-', (width, height))
image_data = convert_to_bytes(image_name, (width, height))
window['-IMAGE-'].update(data=image_data)
window.size = window_size = (width, height)
window.close()
if __name__ == '__main__':
# reset_settings() # if get corrupted problems, uncomment this
main()