Allow window resizing when in single photo mode. Updated the PIL resizing to much more recent resizing code.
This commit is contained in:
parent
5035d24f2c
commit
854bdccdd3
|
@ -1,8 +1,12 @@
|
||||||
import PySimpleGUI as sg
|
import PySimpleGUI as sg
|
||||||
import datetime
|
import datetime
|
||||||
import PIL.Image, PIL.ImageTk
|
import PIL
|
||||||
|
from PIL import Image
|
||||||
import random
|
import random
|
||||||
import os
|
import os
|
||||||
|
import io
|
||||||
|
import base64
|
||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Another simple Desktop Widget using PySimpleGUI
|
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
|
* How long to show the image and if you wnt this time to vary semi-randomly
|
||||||
* Folder containing your images
|
* Folder containing your images
|
||||||
|
|
||||||
Copyright 2021 PySimpleGUI
|
Copyright 2021, 2023 PySimpleGUI
|
||||||
"""
|
"""
|
||||||
|
|
||||||
ALPHA = 0.9 # Initial alpha until user changes
|
ALPHA = 0.9 # Initial alpha until user changes
|
||||||
refresh_font = sg.user_settings_get_entry('-refresh font-', 'Courier 8')
|
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)
|
def make_square(im, fill_color=(0, 0, 0, 0)):
|
||||||
image.thumbnail(resize)
|
x, y = im.size
|
||||||
photo_img = PIL.ImageTk.PhotoImage(image)
|
size = max(x, y)
|
||||||
return photo_img
|
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):
|
def choose_theme(location):
|
||||||
|
@ -43,6 +106,15 @@ def choose_theme(location):
|
||||||
else:
|
else:
|
||||||
return None
|
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):
|
def make_window(location):
|
||||||
alpha = sg.user_settings_get_entry('-alpha-', ALPHA)
|
alpha = sg.user_settings_get_entry('-alpha-', ALPHA)
|
||||||
|
@ -61,7 +133,7 @@ def make_window(location):
|
||||||
layout = [[sg.Image(k='-IMAGE-', enable_events=True)],
|
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)))]]
|
[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
|
return window
|
||||||
|
|
||||||
|
@ -69,11 +141,10 @@ def make_window(location):
|
||||||
def main():
|
def main():
|
||||||
loc = sg.user_settings_get_entry('-location-', (None, None))
|
loc = sg.user_settings_get_entry('-location-', (None, None))
|
||||||
sg.theme(sg.user_settings_get_entry('-theme-', 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)
|
time_per_image = sg.user_settings_get_entry('-time per image-', 60)
|
||||||
vary_randomly = sg.user_settings_get_entry('-random time-', False)
|
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)
|
image_folder = sg.user_settings_get_entry('-image_folder-', None)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -82,36 +153,26 @@ def main():
|
||||||
image_folder = None
|
image_folder = None
|
||||||
sg.user_settings_set_entry('-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:
|
if image_folder is None and single_image is None:
|
||||||
while True:
|
image_name = single_image = sg.popup_get_file('Choose a starting image', keep_on_top=True)
|
||||||
images = None
|
if not single_image:
|
||||||
image_folder = sg.popup_get_folder('Choose location of your images', location=window.current_location(), keep_on_top=True)
|
if sg.popup_yes_no('No folder entered','Go you want to exit the program entirely?', keep_on_top=True) == 'Yes':
|
||||||
if image_folder is not None:
|
exit()
|
||||||
sg.user_settings_set_entry('-image_folder-', image_folder)
|
if image_folder is not None and single_image is None:
|
||||||
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:
|
|
||||||
images = os.listdir(image_folder)
|
images = os.listdir(image_folder)
|
||||||
images = [i for i in images if i.lower().endswith(('.png', '.jpg', '.gif'))]
|
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
|
else: # means single image is not none
|
||||||
images = 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
|
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 --------------
|
# -------------- 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
|
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)
|
event, values = window.read(timeout=timeout)
|
||||||
|
@ -120,6 +181,28 @@ def main():
|
||||||
elif event in (sg.WIN_CLOSE_ATTEMPTED_EVENT, 'Exit'):
|
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
|
sg.user_settings_set_entry('-location-', window.current_location()) # The line of code to save the position before exiting
|
||||||
break
|
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':
|
if event == 'Edit Me':
|
||||||
sg.execute_editor(__file__)
|
sg.execute_editor(__file__)
|
||||||
elif event == 'Choose Image Folder':
|
elif event == 'Choose Image Folder':
|
||||||
|
@ -175,12 +258,15 @@ def main():
|
||||||
window.close()
|
window.close()
|
||||||
window = make_window(loc)
|
window = make_window(loc)
|
||||||
elif event == 'Choose Single Image':
|
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)
|
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()
|
window.close()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
|
# reset_settings() # if get corrupted problems, uncomment this
|
||||||
main()
|
main()
|
Loading…
Reference in New Issue