From d84ee84caf4d442dfd2711189f8073138d51f3bc Mon Sep 17 00:00:00 2001 From: PySimpleGUI Date: Wed, 10 Nov 2021 13:37:11 -0500 Subject: [PATCH] A quick "refresh"... user bsawlor (thank you!) pointed out a float crash. Sliders return floats now and thus needs casting in this demo. --- DemoPrograms/Demo_PNG_Thumbnail_Viewer.py | 90 +++++++++++++++++------ 1 file changed, 68 insertions(+), 22 deletions(-) diff --git a/DemoPrograms/Demo_PNG_Thumbnail_Viewer.py b/DemoPrograms/Demo_PNG_Thumbnail_Viewer.py index 1c21cedb..36e1d8c6 100644 --- a/DemoPrograms/Demo_PNG_Thumbnail_Viewer.py +++ b/DemoPrograms/Demo_PNG_Thumbnail_Viewer.py @@ -1,11 +1,23 @@ #!/usr/bin/env python +import PIL from PIL import Image from sys import exit import PySimpleGUI as sg import os import io -import numpy as np +import base64 +""" + Demo PNG Thumbnail Viewer + + Displays PNG files from a folder. + + OK, so... this isn't the best Demo Program, that's for sure. It's one of the older + demos in the repo. There are likely better ones to use. The convert_to_bytes function is + the best thing in this demo. + + Copyright 2021 PySimpleGUI.org +""" thumbnails = {} @@ -13,28 +25,62 @@ ROWS = 8 COLUMNS = 8 sg.set_options(border_width=0) # Get the folder containing the images from the user -# folder = 'A:/TEMP/pdfs' folder = sg.popup_get_folder('Image folder to open') if folder is None: sg.popup_cancel('Cancelling') exit(0) -def image_file_to_bytes(filename, size): - try: - image = Image.open(filename) - image.thumbnail(size, Image.ANTIALIAS) - bio = io.BytesIO() # a binary memory resident stream - image.save(bio, format='PNG') # save image as png to it - imgbytes = bio.getvalue() - except: - imgbytes = None - return imgbytes + + +def convert_to_bytes(file_or_bytes, resize=None): + """ + 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 file_or_bytes: either a string filename or a bytes base64 image object + :type file_or_bytes: (Union[str, bytes]) + :param resize: optional new size + :type resize: (Tuple[int, int] or None) + :param fill: If True then the image is filled/padded so that the image is not distorted + :type fill: (bool) + :return: (bytes) a byte-string object + :rtype: (bytes) + """ + if isinstance(file_or_bytes, str): + img = PIL.Image.open(file_or_bytes) + else: + try: + img = PIL.Image.open(io.BytesIO(base64.b64decode(file_or_bytes))) + except Exception as e: + dataBytesIO = io.BytesIO(file_or_bytes) + img = PIL.Image.open(dataBytesIO) + + cur_width, cur_height = img.size + if resize: + new_width, new_height = resize + scale = min(new_height / cur_height, new_width / cur_width) + img = img.resize((int(cur_width * scale), int(cur_height * scale)), PIL.Image.ANTIALIAS) + with io.BytesIO() as bio: + img.save(bio, format="PNG") + del img + return bio.getvalue() +# +# old, original PIL code. +# def image_file_to_bytes(filename, size): +# try: +# image = Image.open(filename) +# image.thumbnail(size, Image.ANTIALIAS) +# bio = io.BytesIO() # a binary memory resident stream +# image.save(bio, format='PNG') # save image as png to it +# imgbytes = bio.getvalue() +# except: +# imgbytes = None +# return imgbytes def set_image_to_blank(key): - img = Image.new('RGB', (100, 100), (255, 255, 255)) - img.thumbnail((1, 1), Image.ANTIALIAS) + img = PIL.Image.new('RGB', (100, 100), (255, 255, 255)) + img.thumbnail((1, 1), PIL.Image.ANTIALIAS) bio = io.BytesIO() img.save(bio, format='PNG') imgbytes = bio.getvalue() @@ -43,8 +89,8 @@ def set_image_to_blank(key): # get list of PNG files in folder png_files = [os.path.join(folder, f) - for f in os.listdir(folder) if '.png' in f] -filenames_only = [f for f in os.listdir(folder) if '.png' in f] + for f in os.listdir(folder) if f.endswith('.png')] +filenames_only = [f for f in os.listdir(folder) if f.endswith('.png')] if len(png_files) == 0: sg.popup('No PNG images in folder') @@ -65,7 +111,7 @@ col_buttons = [[]] # define layout, show and read the window col = [[sg.Text(png_files[0], size=(80, 3), key='filename')], - [sg.Image(data=image_file_to_bytes(png_files[0], (500, 500)), key='image')], ] + [sg.Image(data=convert_to_bytes(png_files[0], (500, 500)), key='image')], ] layout = [ [sg.Menu(menu)], @@ -82,11 +128,11 @@ while True: for x in range(ROWS): # update thumbnails for y in range(COLUMNS): - cur_index = display_index + (x * 4) + y + cur_index = display_index + (x * COLUMNS) + y if cur_index < len(png_files): filename = png_files[cur_index] if filename not in thumbnails: - imgbytes = image_file_to_bytes(filename, (100, 100)) + imgbytes = convert_to_bytes(filename, (100, 100)) thumbnails[filename] = imgbytes else: imgbytes = thumbnails[filename] @@ -96,7 +142,7 @@ while True: set_image_to_blank((x, y)) event, values = window.read() - display_index = values['-slider-'] + display_index = int(values['-slider-']) # --------------------- Button & Keyboard --------------------- if event in (sg.WIN_CLOSED, 'Exit'): break @@ -128,10 +174,10 @@ while True: sg.popup('Demo PNG Viewer Program', 'Please give PySimpleGUI a try!') elif type(event) is tuple: x, y = event - image_index = display_index + (x * 4) + y + image_index = display_index + (x * COLUMNS) + y if image_index < len(png_files): filename = png_files[image_index] - imgbytes = image_file_to_bytes(filename, (500, 500)) + imgbytes = convert_to_bytes(filename, (500, 500)) window['image'].update(data=imgbytes) window['filename'].update(filename)