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:
commit
a39e180d13
|
@ -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:
|
||||
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()
|
||||
elif single_image is None:
|
||||
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
|
||||
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"))
|
||||
window = make_window(loc)
|
||||
|
||||
window_size = window.size
|
||||
image_data = convert_to_bytes(image_name, (width, height))
|
||||
|
||||
while True: # 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
|
||||
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()
|
Loading…
Reference in New Issue