Recently I had the need to create a Windows application (EXE) from a Python script, in order to distribute it to some Windows boxes without Python installed. The script implemented a GUI using the Tkinter libraries and I even created a cool logo for the app, so I could replace the default Tkinter logo.
The problem was that I would had to distribute the .exe and the logo (.gif) and it seemed kind of weird. So I thought… why not embed the logo in the script? I could use that to create real self-contained GUI apps in a single Python script!
I’ll share in this post how I achieved this. It’s quite easy.
We have to insert the bytes of the logo file into a Python variable in the script. The best way to do this is to use a byte encoding that outputs printable ASCII characters, so let’s use Base64. You could use many tools to achieve this, I will do it with the base64 command from Linux.
The command will output the bytes of the .gif encoded.
base64 mgx.gif | sed “s/^/logo += ‘/g;s/$/’/g”
To get our logo variable set in our Python script we just have to initialize it and then append the previous output.
logo = '' logo +='R0lGODlhQABAAOf/AAABAAABBQUCBwAEHgQFEQowIHFwIFLQcGGwMFMgwHIQoFRAgHOg0KDwwI' logo +='KwkKJgoHTA0KNg0LMRIMKQ8JXBQHYxIJVg4NPxcxENRBAOUhUSHxEKfBASMREMdRUPTRUKhBEO' logo +='bhESWRUUOhkUNR4JlyMIoBgVQRkUbRcPqR0WVRYRwOsgcVuxsUlR4YaiIPvSEZZh8dTxoZhx8X' logo +='jhUXxiIbgywSySEeeykcfh8Y0RocuSomOygiai8CAcwy4ZvB4grDYV1i8ifiomZioa3ikc1i8g' logo +='qSsmhy4g0SklsjAjui0nni8pizYjtDUe6zQg4yQkojvi0przUpmjIlzDYj3TAwdjsh7y8sqSkp' .......
Perfect. Once we have our variable set, the idea is to write those encoded bytes to a file in run time, and tell Tkinter to read that file as the main icon for our GUI. We can create the file in the same directory but I don’t like this approach because you don’t always have permission to do that. Besides, in my opinion, it’s weird to see that a logo appears in the script’s folder during execution.
I prefer to write it in a temporary file using the cross-platform library tempfile. Here is the code I used for the example.
iconfile = tempfile.NamedTemporaryFile(mode='w+b', delete=False) try: iconfile.write(base64.b64decode(self.logo)) finally: iconfile.close()
In the first line we use the method NamedTemporaryFile to obtain a temporary file with a name so we can read it later. We also set the delete option to False because otherwise the file is deleted as soon it is closed. Then, as you can see, we write the bytes we obtain after decoding our logo variable. Finally we close the file.
Just a couple of things before you see the final code. To obtain the real path generated for the temporary file we have to use the name attribute.
if os.path.isfile(iconfile.name): icon = PhotoImage(file=iconfile.name)
Finally it’s a good practice to tell the OS that we don’t need the file anymore when we close our application.
try: os.unlink(iconfile.name) except: pass
You can view the whole example here –> embedicon.py (411 downloads)
Here are some screenshots of the script in different operating systems.