2018-10-15 20:07:23 +00:00
|
|
|
#!/usr/bin/env python
|
2021-11-10 18:37:11 +00:00
|
|
|
import PIL
|
2019-10-23 20:10:03 +00:00
|
|
|
from PIL import Image
|
|
|
|
from sys import exit
|
|
|
|
import PySimpleGUI as sg
|
2018-10-15 20:07:23 +00:00
|
|
|
import os
|
|
|
|
import io
|
2021-11-10 18:37:11 +00:00
|
|
|
import base64
|
2018-10-15 20:07:23 +00:00
|
|
|
|
2021-11-10 18:37:11 +00:00
|
|
|
"""
|
|
|
|
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
|
|
|
|
"""
|
2018-10-15 20:07:23 +00:00
|
|
|
|
2019-10-23 20:10:03 +00:00
|
|
|
|
|
|
|
thumbnails = {}
|
2018-10-15 20:07:23 +00:00
|
|
|
ROWS = 8
|
|
|
|
COLUMNS = 8
|
2019-10-23 20:10:03 +00:00
|
|
|
sg.set_options(border_width=0)
|
2018-10-15 20:07:23 +00:00
|
|
|
# Get the folder containing the images from the user
|
2019-10-23 20:10:03 +00:00
|
|
|
folder = sg.popup_get_folder('Image folder to open')
|
2018-10-15 20:07:23 +00:00
|
|
|
if folder is None:
|
2019-10-23 20:10:03 +00:00
|
|
|
sg.popup_cancel('Cancelling')
|
2018-10-15 20:07:23 +00:00
|
|
|
exit(0)
|
2019-10-23 20:10:03 +00:00
|
|
|
|
|
|
|
|
2021-11-10 18:37:11 +00:00
|
|
|
|
|
|
|
|
|
|
|
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)
|
2023-10-05 20:26:20 +00:00
|
|
|
img = img.resize((int(cur_width * scale), int(cur_height * scale)), PIL.Image.LANCZOS)
|
2021-11-10 18:37:11 +00:00
|
|
|
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)
|
2023-10-05 20:11:51 +00:00
|
|
|
# image.thumbnail(size, Image.LANCZOS)
|
2021-11-10 18:37:11 +00:00
|
|
|
# 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
|
2018-10-15 20:07:23 +00:00
|
|
|
|
2019-10-23 20:10:03 +00:00
|
|
|
|
2018-10-15 20:07:23 +00:00
|
|
|
def set_image_to_blank(key):
|
2021-11-10 18:37:11 +00:00
|
|
|
img = PIL.Image.new('RGB', (100, 100), (255, 255, 255))
|
2023-10-05 20:26:20 +00:00
|
|
|
img.thumbnail((1, 1), PIL.Image.LANCZOS)
|
2018-10-15 20:07:23 +00:00
|
|
|
bio = io.BytesIO()
|
|
|
|
img.save(bio, format='PNG')
|
|
|
|
imgbytes = bio.getvalue()
|
2019-10-23 20:10:03 +00:00
|
|
|
window[key].update(image_data=imgbytes)
|
2018-10-15 20:07:23 +00:00
|
|
|
|
|
|
|
|
|
|
|
# get list of PNG files in folder
|
2019-10-23 20:10:03 +00:00
|
|
|
png_files = [os.path.join(folder, f)
|
2021-11-10 18:37:11 +00:00
|
|
|
for f in os.listdir(folder) if f.endswith('.png')]
|
|
|
|
filenames_only = [f for f in os.listdir(folder) if f.endswith('.png')]
|
2018-10-15 20:07:23 +00:00
|
|
|
|
|
|
|
if len(png_files) == 0:
|
2019-10-23 20:10:03 +00:00
|
|
|
sg.popup('No PNG images in folder')
|
2018-10-15 20:07:23 +00:00
|
|
|
exit(0)
|
|
|
|
|
|
|
|
# define menu layout
|
2019-10-23 20:10:03 +00:00
|
|
|
menu = [['&File', ['&Open Folder', 'E&xit']], ['&Help', ['&About', ]]]
|
2018-10-15 20:07:23 +00:00
|
|
|
|
|
|
|
buttons = []
|
|
|
|
for display_index in range(ROWS):
|
|
|
|
row = []
|
|
|
|
for j in range(COLUMNS):
|
2019-10-23 20:10:03 +00:00
|
|
|
row.append(sg.Button('', border_width=0,
|
|
|
|
button_color=sg.COLOR_SYSTEM_DEFAULT, key=(display_index, j)))
|
2018-10-15 20:07:23 +00:00
|
|
|
buttons.append(row)
|
|
|
|
|
|
|
|
col_buttons = [[]]
|
|
|
|
|
|
|
|
# define layout, show and read the window
|
|
|
|
col = [[sg.Text(png_files[0], size=(80, 3), key='filename')],
|
2021-11-10 18:37:11 +00:00
|
|
|
[sg.Image(data=convert_to_bytes(png_files[0], (500, 500)), key='image')], ]
|
2019-10-23 20:10:03 +00:00
|
|
|
|
|
|
|
layout = [
|
|
|
|
[sg.Menu(menu)],
|
|
|
|
[sg.Col(buttons), sg.Col([[sg.Slider((len(png_files), 0), default_value=0, size=(38, 20), orientation='v', key='-slider-', change_submits=True)]]), sg.Col(col)]
|
|
|
|
]
|
2018-10-15 20:07:23 +00:00
|
|
|
|
2019-10-23 20:10:03 +00:00
|
|
|
window = sg.Window('Image Browser', layout,
|
2018-10-15 20:07:23 +00:00
|
|
|
return_keyboard_events=True,
|
2019-10-23 20:10:03 +00:00
|
|
|
use_default_focus=False, finalize=True)
|
2018-10-15 20:07:23 +00:00
|
|
|
|
|
|
|
# -------========= Event Loop =========--------
|
2019-10-23 20:10:03 +00:00
|
|
|
display_index = 0
|
2018-10-15 20:07:23 +00:00
|
|
|
while True:
|
2019-10-23 20:10:03 +00:00
|
|
|
|
2018-10-15 20:07:23 +00:00
|
|
|
for x in range(ROWS): # update thumbnails
|
|
|
|
for y in range(COLUMNS):
|
2021-11-10 18:37:11 +00:00
|
|
|
cur_index = display_index + (x * COLUMNS) + y
|
2018-10-15 20:07:23 +00:00
|
|
|
if cur_index < len(png_files):
|
|
|
|
filename = png_files[cur_index]
|
|
|
|
if filename not in thumbnails:
|
2021-11-10 18:37:11 +00:00
|
|
|
imgbytes = convert_to_bytes(filename, (100, 100))
|
2018-10-15 20:07:23 +00:00
|
|
|
thumbnails[filename] = imgbytes
|
|
|
|
else:
|
|
|
|
imgbytes = thumbnails[filename]
|
2019-10-23 20:10:03 +00:00
|
|
|
button_elem = window[(x, y)]
|
|
|
|
button_elem.update(image_data=imgbytes)
|
2018-10-15 20:07:23 +00:00
|
|
|
else:
|
2019-10-23 20:10:03 +00:00
|
|
|
set_image_to_blank((x, y))
|
2018-10-15 20:07:23 +00:00
|
|
|
|
2019-10-23 20:10:03 +00:00
|
|
|
event, values = window.read()
|
2021-11-10 18:37:11 +00:00
|
|
|
display_index = int(values['-slider-'])
|
2018-10-15 20:07:23 +00:00
|
|
|
# --------------------- Button & Keyboard ---------------------
|
2020-05-07 10:22:59 +00:00
|
|
|
if event in (sg.WIN_CLOSED, 'Exit'):
|
2018-10-15 20:07:23 +00:00
|
|
|
break
|
|
|
|
elif event in ('MouseWheel:Down', 'Down:40',) and display_index < len(png_files)-1:
|
|
|
|
display_index += 4
|
|
|
|
elif event in ('MouseWheel:Up', 'Up:38',) and display_index > 0:
|
|
|
|
display_index -= 4
|
|
|
|
elif event in ('Prior:33', 'Prev'):
|
|
|
|
display_index -= 16
|
|
|
|
elif event in ('Next:34', 'Next'):
|
|
|
|
display_index += 16
|
|
|
|
|
2019-10-23 20:10:03 +00:00
|
|
|
window['-slider-'].update(display_index)
|
2018-10-15 20:07:23 +00:00
|
|
|
# ----------------- Menu choices -----------------
|
|
|
|
if event == 'Open Folder':
|
2019-10-23 20:10:03 +00:00
|
|
|
newfolder = sg.popup_get_folder('New folder', no_window=True)
|
2018-10-15 20:07:23 +00:00
|
|
|
if newfolder is None:
|
|
|
|
continue
|
|
|
|
folder = newfolder
|
2019-10-23 20:10:03 +00:00
|
|
|
png_files = [os.path.join(folder, f)
|
|
|
|
for f in os.listdir(folder) if '.png' in f]
|
2018-10-15 20:07:23 +00:00
|
|
|
filenames_only = [f for f in os.listdir(folder) if '.png' in f]
|
|
|
|
display_index = 0
|
|
|
|
thumbnail = {}
|
|
|
|
for j in range(ROWS):
|
|
|
|
for i in range(COLUMNS):
|
2019-10-23 20:10:03 +00:00
|
|
|
set_image_to_blank((i, j))
|
2018-10-15 20:07:23 +00:00
|
|
|
elif event == 'About':
|
2019-10-23 20:10:03 +00:00
|
|
|
sg.popup('Demo PNG Viewer Program', 'Please give PySimpleGUI a try!')
|
2018-10-15 20:07:23 +00:00
|
|
|
elif type(event) is tuple:
|
|
|
|
x, y = event
|
2021-11-10 18:37:11 +00:00
|
|
|
image_index = display_index + (x * COLUMNS) + y
|
2018-10-15 20:07:23 +00:00
|
|
|
if image_index < len(png_files):
|
|
|
|
filename = png_files[image_index]
|
2021-11-10 18:37:11 +00:00
|
|
|
imgbytes = convert_to_bytes(filename, (500, 500))
|
2019-10-23 20:10:03 +00:00
|
|
|
window['image'].update(data=imgbytes)
|
|
|
|
window['filename'].update(filename)
|
2018-10-15 20:07:23 +00:00
|
|
|
|
2019-10-23 20:10:03 +00:00
|
|
|
window.close()
|