11#!/usr/bin/env python
2+ import PIL
23from PIL import Image
34from sys import exit
45import PySimpleGUI as sg
56import os
67import io
7- import numpy as np
8+ import base64
89
10+ """
11+ Demo PNG Thumbnail Viewer
12+
13+ Displays PNG files from a folder.
14+
15+ OK, so... this isn't the best Demo Program, that's for sure. It's one of the older
16+ demos in the repo. There are likely better ones to use. The convert_to_bytes function is
17+ the best thing in this demo.
18+
19+ Copyright 2021 PySimpleGUI.org
20+ """
921
1022
1123thumbnails = {}
1224ROWS = 8
1325COLUMNS = 8
1426sg .set_options (border_width = 0 )
1527# Get the folder containing the images from the user
16- # folder = 'A:/TEMP/pdfs'
1728folder = sg .popup_get_folder ('Image folder to open' )
1829if folder is None :
1930 sg .popup_cancel ('Cancelling' )
2031 exit (0 )
2132
2233
23- def image_file_to_bytes (filename , size ):
24- try :
25- image = Image .open (filename )
26- image .thumbnail (size , Image .ANTIALIAS )
27- bio = io .BytesIO () # a binary memory resident stream
28- image .save (bio , format = 'PNG' ) # save image as png to it
29- imgbytes = bio .getvalue ()
30- except :
31- imgbytes = None
32- return imgbytes
34+
35+
36+ def convert_to_bytes (file_or_bytes , resize = None ):
37+ """
38+ Will convert into bytes and optionally resize an image that is a file or a base64 bytes object.
39+ Turns into PNG format in the process so that can be displayed by tkinter
40+ :param file_or_bytes: either a string filename or a bytes base64 image object
41+ :type file_or_bytes: (Union[str, bytes])
42+ :param resize: optional new size
43+ :type resize: (Tuple[int, int] or None)
44+ :param fill: If True then the image is filled/padded so that the image is not distorted
45+ :type fill: (bool)
46+ :return: (bytes) a byte-string object
47+ :rtype: (bytes)
48+ """
49+ if isinstance (file_or_bytes , str ):
50+ img = PIL .Image .open (file_or_bytes )
51+ else :
52+ try :
53+ img = PIL .Image .open (io .BytesIO (base64 .b64decode (file_or_bytes )))
54+ except Exception as e :
55+ dataBytesIO = io .BytesIO (file_or_bytes )
56+ img = PIL .Image .open (dataBytesIO )
57+
58+ cur_width , cur_height = img .size
59+ if resize :
60+ new_width , new_height = resize
61+ scale = min (new_height / cur_height , new_width / cur_width )
62+ img = img .resize ((int (cur_width * scale ), int (cur_height * scale )), PIL .Image .ANTIALIAS )
63+ with io .BytesIO () as bio :
64+ img .save (bio , format = "PNG" )
65+ del img
66+ return bio .getvalue ()
67+ #
68+ # old, original PIL code.
69+ # def image_file_to_bytes(filename, size):
70+ # try:
71+ # image = Image.open(filename)
72+ # image.thumbnail(size, Image.ANTIALIAS)
73+ # bio = io.BytesIO() # a binary memory resident stream
74+ # image.save(bio, format='PNG') # save image as png to it
75+ # imgbytes = bio.getvalue()
76+ # except:
77+ # imgbytes = None
78+ # return imgbytes
3379
3480
3581def set_image_to_blank (key ):
36- img = Image .new ('RGB' , (100 , 100 ), (255 , 255 , 255 ))
37- img .thumbnail ((1 , 1 ), Image .ANTIALIAS )
82+ img = PIL . Image .new ('RGB' , (100 , 100 ), (255 , 255 , 255 ))
83+ img .thumbnail ((1 , 1 ), PIL . Image .ANTIALIAS )
3884 bio = io .BytesIO ()
3985 img .save (bio , format = 'PNG' )
4086 imgbytes = bio .getvalue ()
@@ -43,8 +89,8 @@ def set_image_to_blank(key):
4389
4490# get list of PNG files in folder
4591png_files = [os .path .join (folder , f )
46- for f in os .listdir (folder ) if '.png' in f ]
47- filenames_only = [f for f in os .listdir (folder ) if '.png' in f ]
92+ for f in os .listdir (folder ) if f . endswith ( '.png' ) ]
93+ filenames_only = [f for f in os .listdir (folder ) if f . endswith ( '.png' ) ]
4894
4995if len (png_files ) == 0 :
5096 sg .popup ('No PNG images in folder' )
@@ -65,7 +111,7 @@ def set_image_to_blank(key):
65111
66112# define layout, show and read the window
67113col = [[sg .Text (png_files [0 ], size = (80 , 3 ), key = 'filename' )],
68- [sg .Image (data = image_file_to_bytes (png_files [0 ], (500 , 500 )), key = 'image' )], ]
114+ [sg .Image (data = convert_to_bytes (png_files [0 ], (500 , 500 )), key = 'image' )], ]
69115
70116layout = [
71117 [sg .Menu (menu )],
@@ -82,11 +128,11 @@ def set_image_to_blank(key):
82128
83129 for x in range (ROWS ): # update thumbnails
84130 for y in range (COLUMNS ):
85- cur_index = display_index + (x * 4 ) + y
131+ cur_index = display_index + (x * COLUMNS ) + y
86132 if cur_index < len (png_files ):
87133 filename = png_files [cur_index ]
88134 if filename not in thumbnails :
89- imgbytes = image_file_to_bytes (filename , (100 , 100 ))
135+ imgbytes = convert_to_bytes (filename , (100 , 100 ))
90136 thumbnails [filename ] = imgbytes
91137 else :
92138 imgbytes = thumbnails [filename ]
@@ -96,7 +142,7 @@ def set_image_to_blank(key):
96142 set_image_to_blank ((x , y ))
97143
98144 event , values = window .read ()
99- display_index = values ['-slider-' ]
145+ display_index = int ( values ['-slider-' ])
100146 # --------------------- Button & Keyboard ---------------------
101147 if event in (sg .WIN_CLOSED , 'Exit' ):
102148 break
@@ -128,10 +174,10 @@ def set_image_to_blank(key):
128174 sg .popup ('Demo PNG Viewer Program' , 'Please give PySimpleGUI a try!' )
129175 elif type (event ) is tuple :
130176 x , y = event
131- image_index = display_index + (x * 4 ) + y
177+ image_index = display_index + (x * COLUMNS ) + y
132178 if image_index < len (png_files ):
133179 filename = png_files [image_index ]
134- imgbytes = image_file_to_bytes (filename , (500 , 500 ))
180+ imgbytes = convert_to_bytes (filename , (500 , 500 ))
135181 window ['image' ].update (data = imgbytes )
136182 window ['filename' ].update (filename )
137183
0 commit comments