121 lines
4.2 KiB
Python
121 lines
4.2 KiB
Python
#!/usr/bin/env python
|
|
import sys
|
|
if sys.version_info[0] >= 3:
|
|
import PySimpleGUI as sg
|
|
else:
|
|
import PySimpleGUI27 as sg
|
|
import os
|
|
from PIL import Image, ImageTk
|
|
import io
|
|
"""
|
|
Simple Image Browser based on PySimpleGUI
|
|
--------------------------------------------
|
|
There are some improvements compared to the PNG browser of the repository:
|
|
1. Paging is cyclic, i.e. automatically wraps around if file index is outside
|
|
2. Supports all file types that are valid PIL images
|
|
3. Limits the maximum form size to the physical screen
|
|
4. When selecting an image from the listbox, subsequent paging uses its index
|
|
5. Paging performance improved significantly because of using PIL
|
|
|
|
Dependecies
|
|
------------
|
|
Python v3
|
|
PIL
|
|
"""
|
|
# Get the folder containing the images from the user
|
|
rc, folder = sg.GetPathBox('Image Browser', 'Image folder to open', default_path='')
|
|
if not rc or not folder:
|
|
sg.PopupCancel('Cancelling')
|
|
raise SystemExit()
|
|
|
|
# PIL supported image types
|
|
img_types = (".png", ".jpg", "jpeg", ".tiff", ".bmp")
|
|
|
|
# get list of files in folder
|
|
flist0 = os.listdir(folder)
|
|
|
|
# create sub list of image files (no sub folders, no wrong file types)
|
|
fnames = [f for f in flist0 if os.path.isfile(os.path.join(folder,f)) and f.lower().endswith(img_types)]
|
|
|
|
num_files = len(fnames) # number of iamges found
|
|
if num_files == 0:
|
|
sg.Popup('No files in folder')
|
|
raise SystemExit()
|
|
|
|
del flist0 # no longer needed
|
|
|
|
#------------------------------------------------------------------------------
|
|
# use PIL to read data of one image
|
|
#------------------------------------------------------------------------------
|
|
def get_img_data(f, maxsize = (1200, 850), first = False):
|
|
"""Generate image data using PIL
|
|
"""
|
|
img = Image.open(f)
|
|
img.thumbnail(maxsize)
|
|
if first: # tkinter is inactive the first time
|
|
bio = io.BytesIO()
|
|
img.save(bio, format = "PNG")
|
|
del img
|
|
return bio.getvalue()
|
|
return ImageTk.PhotoImage(img)
|
|
#------------------------------------------------------------------------------
|
|
|
|
|
|
# create the form that also returns keyboard events
|
|
window = sg.Window('Image Browser', return_keyboard_events=True,
|
|
location=(0, 0), use_default_focus=False)
|
|
|
|
# make these 2 elements outside the layout as we want to "update" them later
|
|
# initialize to the first file in the list
|
|
filename = os.path.join(folder, fnames[0]) # name of first file in list
|
|
image_elem = sg.Image(data = get_img_data(filename, first = True))
|
|
filename_display_elem = sg.Text(filename, size=(80, 3))
|
|
file_num_display_elem = sg.Text('File 1 of {}'.format(num_files), size=(15,1))
|
|
|
|
# define layout, show and read the form
|
|
col = [[filename_display_elem],
|
|
[image_elem]]
|
|
|
|
col_files = [[sg.Listbox(values = fnames, change_submits=True, size=(60, 30), key='listbox')],
|
|
[sg.ReadButton('Next', size=(8,2)), sg.ReadButton('Prev',
|
|
size=(8,2)), file_num_display_elem]]
|
|
|
|
layout = [[sg.Column(col_files), sg.Column(col)]]
|
|
|
|
window.Layout(layout) # Shows form on screen
|
|
|
|
# loop reading the user input and displaying image, filename
|
|
i=0
|
|
while True:
|
|
# read the form
|
|
button, values = window.Read()
|
|
|
|
# perform button and keyboard operations
|
|
if button is None:
|
|
break
|
|
elif button in ('Next', 'MouseWheel:Down', 'Down:40', 'Next:34'):
|
|
i += 1
|
|
if i >= num_files:
|
|
i -= num_files
|
|
filename = os.path.join(folder, fnames[i])
|
|
elif button in ('Prev', 'MouseWheel:Up', 'Up:38', 'Prior:33'):
|
|
i -= 1
|
|
if i < 0:
|
|
i = num_files + i
|
|
filename = os.path.join(folder, fnames[i])
|
|
elif button in ('Read', ''): # something from the listbox
|
|
f = values["listbox"][0] # selected filename
|
|
filename = os.path.join(folder, f) # read this file
|
|
i = fnames.index(f) # update running index
|
|
else:
|
|
filename = os.path.join(folder, fnames[i])
|
|
|
|
# update window with new image
|
|
image_elem.Update(data=get_img_data(filename))
|
|
# update window with filename
|
|
filename_display_elem.Update(filename)
|
|
# update page display
|
|
file_num_display_elem.Update('File {} of {}'.format(i+1, num_files))
|
|
|
|
|