Posts Tagged ‘tempfile’

August 21st, 2014  Posted at   Languages, Python

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.

For this example I’ve created a very simple logo (64×64 pixels) online using cooltext.com and I exported it in GIF format because it’s the appropriated one for this method. Here it is ‘mgx.gif’:

mgx.gif

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.

base64 mgx.gif

The command will output the bytes of the .gif encoded.

base64

Now we have to assign the Base64 string to a Python variable. We will use the power of sed and Regular Expressions to make our life easier. Suppose our variable will be called ‘logo’.

base64 mgx.gif | sed “s/^/logo += ‘/g;s/$/’/g”

base64_sed

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

Here are some screenshots of the script in different operating systems.

embedded_xp

Windows XP

embedded_w7

Windows 7

embedded_ubuntu

Ubuntu

embedded_kali

Kali Linux

 

Enjoy :)