psgresizer demo updated both in Demo Programs and in the new standalone repo as well as on PyPI

This commit is contained in:
PySimpleGUI 2021-11-16 08:46:47 -05:00
parent 9b8b33636d
commit f92df8c419
1 changed files with 152 additions and 51 deletions

View File

@ -1,85 +1,176 @@
import PySimpleGUI as sg import PySimpleGUI as sg
from PIL import Image from PIL import Image
import PIL
import os import os
import base64 import base64
import io
import webbrowser
""" """
Demo Image Resize and Base64 Encode 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. 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: Use this Demo to help you code your PySimpleGUI programs. Here's how:
1. Resize your image 1. Select PNG as the output format
2. Paste the base64 encoded byte-string into your code as a variable 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. 3. Use your variable for things like an icon, an image for buttons, etc.
Copyright 2021 PySimpleGUI 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) image = Image.open(input_file)
width, height = image.size width, height = image.size
print(f"The original image size is {width} wide x {height} high")
new_width, new_height = size new_width, new_height = size
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) scale = min(new_height / height, new_width / width)
resized_image = image.resize((int(width * scale), int(height * scale)), Image.ANTIALIAS) resized_image = image.resize((int(width * scale), int(height * scale)), Image.ANTIALIAS)
# resized_image = image.resize(size) else:
width, height = resized_image.size resized_image = image
print(f"The resized image size is {width} wide x {height} high")
if output_file is not None:
resized_image.save(output_file) resized_image.save(output_file)
def convert_file_to_base64(filename): # encode a PNG formatted version of image into BASE64
try: with io.BytesIO() as bio:
contents = open(filename, 'rb').read() resized_image.save(bio, format=encode_format)
contents = bio.getvalue()
encoded = base64.b64encode(contents) encoded = base64.b64encode(contents)
sg.clipboard_set(encoded) return 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)
def main(): def main():
image_resize_icon = b'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'
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')], layout = [[sg.Text('Image Resizer')],
[sg.Frame('Input Image', [[sg.Input(key='-IN-', enable_events=True), sg.FileBrowse()], [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.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.Frame('Output Filename', [[sg.In(k='-NEW FILENAME-', s=80), sg.FileBrowse(), ],
[sg.CBox('Encode to Base64 and leave on Clipboard', default=True,k='-BASE64-')], [sg.In(default_text=sg.user_settings_get_entry('-width-', ''), s=4, k='-WIDTH-'), sg.T('X'),
[sg.CBox('Autoclose Immediately When Done', default=sg.user_settings_get_entry('-autoclose-', True if sg.running_windows() else False),k='-AUTOCLOSE-')], 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.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')],] [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')],
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) [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: while True:
event, values = window.read() event, values = window.read()
# print(event, values) # print(event, values)
if event in (sg.WIN_CLOSED, sg.WIN_CLOSE_ATTEMPTED_EVENT, 'Exit'): if event in (sg.WIN_CLOSED, sg.WIN_CLOSE_ATTEMPTED_EVENT, 'Exit'):
sg.user_settings_set_entry('-autoclose-', values['-AUTOCLOSE-'])
break break
sg.user_settings_set_entry('-autoclose-', values['-AUTOCLOSE-'])
infile = values['-IN-'] infile = values['-IN-']
if event == '-IN-': update_outfilename()
if os.path.isfile(infile):
image = Image.open(infile) if event == '-DO NOT SAVE-':
window['-ORIG WIDTH-'].update(image.size[0]) if values['-DO NOT SAVE-']:
window['-ORIG HEIGHT-'].update(image.size[1]) window['-NEW FILENAME-'].update('')
window['-BASE64-'].update(True)
if event == 'Resize': if event == 'Resize':
try:
if os.path.isfile(infile): if os.path.isfile(infile):
update_outfilename()
infilename = os.path.basename(infile) infilename = os.path.basename(infile)
infilenameonly, infileext = os.path.splitext(infilename) infilenameonly, infileext = os.path.splitext(infilename)
try: 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-']) width, height = int(values['-WIDTH-']), int(values['-HEIGHT-'])
outfile = f'{infilenameonly}{width}x{height}{infileext}' if values['-DO NOT SAVE-']:
outfullfilename = os.path.join(os.path.dirname(infile), outfile) encoded = resize(input_file=infile, size=(width, height), output_file=None, encode_format=encode_format)
resize(input_file=infile, output_file=outfullfilename, size=(width, height)) else:
encoded = resize(input_file=infile, size=(width, height), output_file=outfullfilename, encode_format=encode_format)
if values['-BASE64-']: if values['-BASE64-']:
convert_file_to_base64(outfullfilename) sg.clipboard_set(encoded)
sg.popup_quick_message('DONE!', font='_ 40', background_color='red', text_color='white')
except Exception as e: except Exception as e:
sg.popup_error_with_traceback('Error resizing or converting', 'Error encountered during the resize or Base64 encoding', 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 values['-AUTOCLOSE-']:
if sg.user_settings_get_entry('-autoclose-'):
break break
elif event == 'Version': elif event == 'Version':
sg.popup_scrolled(sg.get_versions(), non_blocking=True) sg.popup_scrolled(sg.get_versions(), non_blocking=True)
@ -87,10 +178,20 @@ def main():
sg.execute_editor(__file__) sg.execute_editor(__file__)
elif event == 'File Location': elif event == 'File Location':
sg.popup_scrolled('This Python file is:', __file__) 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() window.close()
if __name__ == '__main__': if __name__ == '__main__':
image_resize_icon = b'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'
main() main()