Merge pull request #6473 from PySimpleGUI/Dev-latest

Allow window resizing when in single photo mode.  Updated the PIL res…
This commit is contained in:
PySimpleGUI 2023-08-10 12:45:21 -04:00 committed by GitHub
commit a39e180d13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 123 additions and 37 deletions

View File

@ -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()