Merge pull request #4966 from PySimpleGUI/Dev-latest

psgresizer demo updated both in Demo Programs and in the new standalo…
This commit is contained in:
PySimpleGUI 2021-11-16 08:47:12 -05:00 committed by GitHub
commit 1ed6e56c86
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 152 additions and 51 deletions

View File

@ -1,96 +1,197 @@
import PySimpleGUI as sg
from PIL import Image
import PIL
import os
import base64
import io
import webbrowser
"""
Demo Image Resize and Base64 Encode
A quick little utility that will resize an image and also Base64 Encode it.
This demo has been released to PyPI as the commnand `psgresizer`. It is also in in this repo:
https://github.com/PySimpleGUI/psgresizer
A quick little utility that will resize an image, convert between formats, and also Base64 Encode it.
Base64 is particularly good to use to make icons or other images that you include in your sourcecode.
Use this Demo to help you code your PySimpleGUI programs. Here's how:
1. Resize your image
2. Paste the base64 encoded byte-string into your code as a variable
1. Select PNG as the output format
2. Set "Encode to Base64" checkbox to True
2. Click resize button
2. Paste the base64 encoded byte-string left on the clipboard into your code as a variable
3. Use your variable for things like an icon, an image for buttons, etc.
Copyright 2021 PySimpleGUI
"""
def resize(input_file, output_file, size):
version = '1.3.1'
__version__ = version.split()[0]
'''
Change log
1.3.1 16-Nov-2021
Added correct readme to PyPI
1.3.0 16-Nov-2021
Fixed bug - MUST always include the icon in the main function for these psg commands
1.2.0 16-Nov-2021
Somewhat extensive reworking of the functionality
Added a drop-down list of formats to convert to
Automatically save all the settings
And more I'm sure!
'''
def resize(input_file, size, output_file=None, encode_format='PNG'):
image = Image.open(input_file)
width, height = image.size
print(f"The original image size is {width} wide x {height} high")
new_width, new_height = size
scale = min(new_height / height, new_width / width)
resized_image = image.resize((int(width * scale), int(height * scale)), Image.ANTIALIAS)
# resized_image = image.resize(size)
width, height = resized_image.size
print(f"The resized image size is {width} wide x {height} high")
resized_image.save(output_file)
if new_width != width or new_height != height: # if the requested size is different than original size
scale = min(new_height / height, new_width / width)
resized_image = image.resize((int(width * scale), int(height * scale)), Image.ANTIALIAS)
else:
resized_image = image
def convert_file_to_base64(filename):
try:
contents = open(filename, 'rb').read()
if output_file is not None:
resized_image.save(output_file)
# encode a PNG formatted version of image into BASE64
with io.BytesIO() as bio:
resized_image.save(bio, format=encode_format)
contents = bio.getvalue()
encoded = base64.b64encode(contents)
sg.clipboard_set(encoded)
if not sg.user_settings_get_entry('-autoclose-'):
sg.popup('Copied to your clipboard!', 'Keep program open until you have pasted the base64 bytestring', auto_close=True, auto_close_duration=4)
except Exception as error:
sg.popup_error('Cancelled - An error occurred', error)
return encoded
def main():
layout = [ [sg.Text('Image Resizer')],
[sg.Frame('Input Image', [[sg.Input(key='-IN-', enable_events=True), sg.FileBrowse()],
[sg.T('Original size'), sg.T(k='-ORIG WIDTH-'), sg.T('X'), sg.T(k='-ORIG HEIGHT-')]])],
[sg.Frame('New Size', [[sg.In(50, s=4, k='-WIDTH-'), sg.T('X'), sg.In(50, s=4, k='-HEIGHT-')]])],
[sg.CBox('Encode to Base64 and leave on Clipboard', default=True,k='-BASE64-')],
[sg.CBox('Autoclose Immediately When Done', default=sg.user_settings_get_entry('-autoclose-', True if sg.running_windows() else False),k='-AUTOCLOSE-')],
[sg.Button('Resize', bind_return_key=True), sg.Button('Exit')],
[sg.T('Note - on some systems, autoclose cannot be used\nbecause the clipboard is cleared by tkinter')],]
image_resize_icon = b'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'
window = sg.Window('Resize Image', layout, icon=image_resize_icon, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_LOC_EXIT, enable_close_attempted_event=True)
def update_outfilename():
infile = values['-IN-']
if os.path.isfile(infile):
image = Image.open(infile)
width, height = image.size
window['-ORIG WIDTH-'].update(image.size[0])
if not values['-WIDTH-']:
window['-WIDTH-'].update(image.size[0])
if not values['-HEIGHT-']:
window['-HEIGHT-'].update(image.size[1])
window['-ORIG HEIGHT-'].update(image.size[1])
infilename = os.path.basename(infile)
infilenameonly, infileext = os.path.splitext(infilename)
if values['-NEW FORMAT-']:
outfileext = values['-NEW FORMAT-'].lower()
if outfileext == 'jpeg':
outfileext = 'jpg'
else:
outfileext = infileext[1:] # strip off the .
outfile = f'{infilenameonly}{width}x{height}.{outfileext}'
outfullfilename = os.path.join(os.path.dirname(infile), outfile)
if values['-DO NOT SAVE-']:
window['-NEW FILENAME-'].update('')
window['-BASE64-'].update(True)
else:
window['-NEW FILENAME-'].update(outfullfilename)
else:
window['-NEW FILENAME-'].update('')
window['-ORIG WIDTH-'].update('')
# window['-WIDTH-'].update('')
window['-ORIG HEIGHT-'].update('')
# window['-HEIGHT-'].update('')
window['-NEW FILENAME-'].update()
format_list = ('', 'PNG', 'JPEG', 'BMP', 'ICO', 'GIF', 'TIFF')
new_format_layout = [
[sg.Combo(format_list, default_value=sg.user_settings_get_entry('-new format-', ''), readonly=True, enable_events=True, key='-NEW FORMAT-')]]
layout = [[sg.Text('Image Resizer')],
[sg.Frame('Input Filename', [[sg.Input(key='-IN-', enable_events=True, s=80), sg.FileBrowse(), ],
[sg.T('Original size'), sg.T(k='-ORIG WIDTH-'), sg.T('X'), sg.T(k='-ORIG HEIGHT-')]])],
[sg.Frame('Output Filename', [[sg.In(k='-NEW FILENAME-', s=80), sg.FileBrowse(), ],
[sg.In(default_text=sg.user_settings_get_entry('-width-', ''), s=4, k='-WIDTH-'), sg.T('X'),
sg.In(default_text=sg.user_settings_get_entry('-height-', ''), s=4, k='-HEIGHT-')]])],
[sg.Frame('Convert To New Format', new_format_layout)],
[sg.CBox('Encode to Base64 and leave on Clipboard', k='-BASE64-', default=sg.user_settings_get_entry('-base64-', True))],
# [sg.CBox('Use PNG for all Base64 Encoding', default=True, k='-PNG CONVERT-')],
[sg.CBox('Do not save file - Only convert and Base64 Encode', k='-DO NOT SAVE-', enable_events=True,
default=sg.user_settings_get_entry('-do not save-', False))],
[sg.CBox('Autoclose Immediately When Done', default=sg.user_settings_get_entry('-autoclose-', True if sg.running_windows() else False),
k='-AUTOCLOSE-')],
[sg.Button('Resize', bind_return_key=True), sg.Button('Exit')],
[sg.T('Note - on some systems, autoclose cannot be used because the clipboard is cleared by tkinter')],
[sg.T('Your settings are automatically saved between runs')],
[sg.T(f'Version {version}'), sg.T('Go to psgresizer GitHub Repo', font='_ 8', enable_events=True, k='-PSGRESIZER-'),
sg.T('A PySimpleGUI Application - Go to PySimpleGUI home', font='_ 8', enable_events=True, k='-PYSIMPLEGUI-')],
]
window = sg.Window('Resize Image', layout, icon=image_resize_icon, right_click_menu=sg.MENU_RIGHT_CLICK_EDITME_VER_LOC_EXIT,
enable_close_attempted_event=True, finalize=True)
window['-PSGRESIZER-'].set_cursor('hand1')
window['-PYSIMPLEGUI-'].set_cursor('hand1')
while True:
event, values = window.read()
# print(event, values)
if event in (sg.WIN_CLOSED, sg.WIN_CLOSE_ATTEMPTED_EVENT, 'Exit'):
sg.user_settings_set_entry('-autoclose-', values['-AUTOCLOSE-'])
break
sg.user_settings_set_entry('-autoclose-', values['-AUTOCLOSE-'])
infile = values['-IN-']
if event == '-IN-':
if os.path.isfile(infile):
image = Image.open(infile)
window['-ORIG WIDTH-'].update(image.size[0])
window['-ORIG HEIGHT-'].update(image.size[1])
update_outfilename()
if event == '-DO NOT SAVE-':
if values['-DO NOT SAVE-']:
window['-NEW FILENAME-'].update('')
window['-BASE64-'].update(True)
if event == 'Resize':
if os.path.isfile(infile):
infilename = os.path.basename(infile)
infilenameonly, infileext = os.path.splitext(infilename)
try:
try:
if os.path.isfile(infile):
update_outfilename()
infilename = os.path.basename(infile)
infilenameonly, infileext = os.path.splitext(infilename)
if values['-NEW FORMAT-']:
encode_format = values['-NEW FORMAT-'].upper()
else:
encode_format = infileext[1:].upper() # strip off the .
if encode_format == 'JPG':
encode_format = 'JPEG'
outfullfilename = values['-NEW FILENAME-']
width, height = int(values['-WIDTH-']), int(values['-HEIGHT-'])
outfile = f'{infilenameonly}{width}x{height}{infileext}'
outfullfilename = os.path.join(os.path.dirname(infile), outfile)
resize(input_file=infile, output_file=outfullfilename, size=(width, height))
if values['-DO NOT SAVE-']:
encoded = resize(input_file=infile, size=(width, height), output_file=None, encode_format=encode_format)
else:
encoded = resize(input_file=infile, size=(width, height), output_file=outfullfilename, encode_format=encode_format)
if values['-BASE64-']:
convert_file_to_base64(outfullfilename)
except Exception as e:
sg.popup_error_with_traceback('Error resizing or converting', 'Error encountered during the resize or Base64 encoding', e)
sg.popup_quick_message('DONE!', font='_ 40', background_color='red', text_color='white')
if sg.user_settings_get_entry('-autoclose-'):
break
sg.clipboard_set(encoded)
sg.popup_quick_message('DONE!', font='_ 40', background_color='red', text_color='white')
except Exception as e:
sg.popup_error_with_traceback('Error resizing or converting', 'Error encountered during the resize or Base64 encoding', e)
if values['-AUTOCLOSE-']:
break
elif event == 'Version':
sg.popup_scrolled(sg.get_versions(), non_blocking=True)
elif event == 'Edit Me':
sg.execute_editor(__file__)
elif event == 'File Location':
sg.popup_scrolled('This Python file is:', __file__)
elif event == '-PYSIMPLEGUI-':
webbrowser.open_new_tab(r'http://www.PySimpleGUI.com')
elif event == '-PSGRESIZER-':
webbrowser.open_new_tab(r'https://github.com/PySimpleGUI/psgresizer')
if event != sg.WIN_CLOSED:
sg.user_settings_set_entry('-autoclose-', values['-AUTOCLOSE-'])
sg.user_settings_set_entry('-new format-', values['-NEW FORMAT-'])
sg.user_settings_set_entry('-do not save-', values['-DO NOT SAVE-'])
sg.user_settings_set_entry('-base64-', values['-BASE64-'])
sg.user_settings_set_entry('-width-', values['-WIDTH-'])
sg.user_settings_set_entry('-height-', values['-HEIGHT-'])
window.close()
if __name__ == '__main__':
image_resize_icon = b'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'
main()