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 changed files with 123 additions and 37 deletions
				
			
		|  | @ -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 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': |             if sg.popup_yes_no('No folder entered','Go you want to exit the program entirely?', keep_on_top=True) == 'Yes': | ||||||
|                 exit() |                 exit() | ||||||
|     elif single_image is None: |     if image_folder is not None and 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 | ||||||
|     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_name = single_image | ||||||
|             image_data = convert_to_bytes(single_image, (width, height)) |     window = make_window(loc) | ||||||
|         window['-FILENAME-'].update(image_name) | 
 | ||||||
|         window['-IMAGE-'].update(data=image_data) |     window_size = window.size | ||||||
|         window['-REFRESHED-'].update(datetime.datetime.now().strftime("%m/%d/%Y %I:%M:%S %p")) |     image_data = convert_to_bytes(image_name, (width, height)) | ||||||
|  | 
 | ||||||
|  |     while True:  # Event Loop | ||||||
|         # -------------- 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…
	
	Add table
		Add a link
		
	
		Reference in a new issue