import PySimpleGUI as sg from PIL import Image import PIL import os import base64 import io import webbrowser """ Demo Image Resize and Base64 Encode 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. 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 """ 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 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) resized_image = image.resize((int(width * scale), int(height * scale)), Image.ANTIALIAS) else: resized_image = image 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) return encoded 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')], [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'): break infile = values['-IN-'] update_outfilename() if event == '-DO NOT SAVE-': if values['-DO NOT SAVE-']: window['-NEW FILENAME-'].update('') window['-BASE64-'].update(True) if event == 'Resize': 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-']) 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-']: 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__': main()