2021-01-24 16:20:11 +00:00
|
|
|
import PySimpleGUI as sg
|
|
|
|
import PIL
|
|
|
|
from PIL import Image
|
|
|
|
import io
|
|
|
|
import base64
|
2021-02-02 01:37:56 +00:00
|
|
|
import random
|
2021-01-24 16:20:11 +00:00
|
|
|
|
|
|
|
"""
|
|
|
|
Using PIL with PySimpleGUI - for Images and Buttons
|
|
|
|
|
|
|
|
The reason for this demo is to give you this nice PIL based function - convert_to_bytes
|
|
|
|
|
|
|
|
This function is your gateway to using any format of image (not just PNG & GIF) and to
|
|
|
|
resize / convert it so that it can be used with the Button and Image elements.
|
|
|
|
|
2022-12-07 15:07:01 +00:00
|
|
|
Copyright 2020, 2022 PySimpleGUI.org
|
2021-01-24 16:20:11 +00:00
|
|
|
"""
|
|
|
|
|
2022-12-07 15:07:01 +00:00
|
|
|
def make_square(im, fill_color=(0, 0, 0, 0)):
|
2021-02-01 20:08:13 +00:00
|
|
|
x, y = im.size
|
2022-12-07 15:07:01 +00:00
|
|
|
size = max(x, y)
|
2021-02-01 20:08:13 +00:00
|
|
|
new_im = Image.new('RGBA', (size, size), fill_color)
|
|
|
|
new_im.paste(im, (int((size - x) / 2), int((size - y) / 2)))
|
|
|
|
return new_im
|
|
|
|
|
|
|
|
|
2022-12-07 15:07:01 +00:00
|
|
|
|
|
|
|
def convert_to_bytes(source, size=(None, None), subsample=None, zoom=None, fill=False):
|
2021-02-02 01:37:56 +00:00
|
|
|
"""
|
2021-01-24 16:20:11 +00:00
|
|
|
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
|
2022-12-07 15:07:01 +00:00
|
|
|
: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
|
2021-01-24 16:20:11 +00:00
|
|
|
:type fill: (bool)
|
|
|
|
:return: (bytes) a byte-string object
|
|
|
|
:rtype: (bytes)
|
2021-02-02 01:37:56 +00:00
|
|
|
"""
|
2022-12-07 15:07:01 +00:00
|
|
|
if isinstance(source, str):
|
|
|
|
image = Image.open(source)
|
|
|
|
elif isinstance(source, bytes):
|
|
|
|
image = Image.open(io.BytesIO(base64.b64decode(source)))
|
2021-01-24 16:20:11 +00:00
|
|
|
else:
|
2022-12-07 15:07:01 +00:00
|
|
|
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
|
2021-01-24 16:20:11 +00:00
|
|
|
with io.BytesIO() as bio:
|
2022-12-07 15:07:01 +00:00
|
|
|
resized_image.save(bio, format="PNG")
|
|
|
|
contents = bio.getvalue()
|
|
|
|
encoded = base64.b64encode(contents)
|
|
|
|
return encoded
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-01-24 16:20:11 +00:00
|
|
|
|
2021-02-02 01:37:56 +00:00
|
|
|
def random_image():
|
2021-05-24 13:46:24 +00:00
|
|
|
return random.choice(sg.EMOJI_BASE64_LIST)
|
2021-01-24 16:20:11 +00:00
|
|
|
|
|
|
|
def make_toolbar():
|
|
|
|
layout = [[sg.T('❎', enable_events=True, key='Exit')]]
|
|
|
|
for i in range(6):
|
2021-02-02 01:37:56 +00:00
|
|
|
layout += [[sg.B(image_data = convert_to_bytes(random_image(), (30,30))),
|
|
|
|
sg.B(image_data = convert_to_bytes(random_image(), (30,30)))]]
|
2021-01-24 16:20:11 +00:00
|
|
|
return sg.Window('', layout, element_padding=(0,0), margins=(0,0), finalize=True, no_titlebar=True, grab_anywhere=True)
|
|
|
|
|
|
|
|
def main():
|
|
|
|
|
2021-02-02 01:37:56 +00:00
|
|
|
image = random_image()
|
2021-01-24 16:20:11 +00:00
|
|
|
size = (60,60)
|
2021-02-01 20:08:13 +00:00
|
|
|
image = convert_to_bytes(image, size, fill=False)
|
2021-01-24 16:20:11 +00:00
|
|
|
|
|
|
|
layout = [[sg.Button('+', size=(4,2)), sg.Button('-', size=(4,2)), sg.B('Next', size=(4,2)), sg.T(size, size=(10,1), k='-SIZE-')],
|
|
|
|
[sg.Image(data=image, k='-IMAGE-')],
|
|
|
|
[sg.Button(image_data=image, key='-BUTTON IMAGE-')],]
|
|
|
|
|
|
|
|
window = sg.Window('Window Title', layout, finalize=True)
|
|
|
|
toolbar = make_toolbar()
|
|
|
|
|
|
|
|
while True: # Event Loop
|
|
|
|
event_window, event, values = sg.read_all_windows()
|
|
|
|
if event == sg.WIN_CLOSED or event == 'Exit':
|
|
|
|
break
|
|
|
|
if event == '+':
|
|
|
|
size = (size[0]+20, size[1]+20)
|
|
|
|
elif event == '-':
|
|
|
|
if size[0] > 20:
|
|
|
|
size = (size[0]-20, size[1]-20)
|
|
|
|
elif event in ('Next', '-BUTTON IMAGE-'):
|
2021-05-24 13:46:24 +00:00
|
|
|
image = random.choice(sg.EMOJI_BASE64_LIST)
|
2021-01-24 16:20:11 +00:00
|
|
|
elif event_window == toolbar:
|
|
|
|
image = event_window[event].ImageData
|
|
|
|
|
|
|
|
# Resize image and update the window
|
2021-02-01 20:08:13 +00:00
|
|
|
image = convert_to_bytes(image, size, fill=True)
|
2021-01-24 16:20:11 +00:00
|
|
|
window['-IMAGE-'].update(data=image)
|
|
|
|
window['-BUTTON IMAGE-'].update(image_data=image)
|
|
|
|
window['-SIZE-'].update(size)
|
|
|
|
window.close()
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
2021-02-01 20:08:13 +00:00
|
|
|
main()
|