How to embed icon data in Python 3.x for TkInter

Sometimes when you want to use TKinter or other GUI dialog but you don’t want to use the generic default icon. You also might not want to have the *.ico or *.png file included in the same folder as your script. Wouldn’t it be nice to just have the icon data embedded in your code?

It’s actually not too difficult to do in Python. I’m working with Python 3.x here so you might have to adjust the code for Python 2.x. We’ll use Tkinter dialog as an example here. Let’s try putting this example books.icon or any icon you would like to use in code. If you need icons to play with, you can get a great set of open-sourced icons from here:
https://sourceforge.net/projects/openiconlibrary/

The icon I’m using is from the icon pack and once you extract the archive, it’s in ../ico/16×16/others/books.ico. You can also just download the icon file here: books.ico

books.ico

The trick is to converting the icon file data into string representation of hex data that we can store in the program. This is actually surprisingly easy to do using repr() function to generate string of the object. In this case, we are converting the icon image data into string hex values. The following code will print out the data for the icon file in the almost correct format for you to use. Make sure the icon file is in the same location as your script when running this code.

with open("books.ico", "rb") as image:
     a = image.read()
print(repr(a))

I said almost a correct format because you’ll end up with a really long string hex data dump and it’s in a single line. This could be used as-is but you’ll end up with a really long line in your python file that you’ll have to scroll right very far to see the entire thing. I’m truncating here so we don’t fill up the whole page.

b'\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x00\x00\x00\x00h\x04\x00\x00\x16\x00\x00\x00(\x00\x00\x00\x10\x00\x00\x00 \x00\x00\x00\x01\x00 
... 
f00\x00\xf0\x03\x00\x00\xfe\x1f\x00\x00\xff\xff\x00\x00'

For the sake of readability in our code, we’ll format it into a nicer format by breaking every 16th hex values into its own line. Here’s the previous code updated with a formatting code below:

with open("books.ico", "rb") as image:
    a = image.read()
data = (repr(a))

data = data[2:]  #trim out the b'
data = data[:-1]  #trim out the last '

dataList = data.split('\\x')  #split by hex unit
dataList = dataList[1:] #remove the blank  value at the beginning

totalLen = len(dataList)

i = 0
hexline = ''
lenCount = 0
groupCount = 0
for hex in dataList:
    if(lenCount == totalLen-1):
        hexline += '\\x' + hex
        print('b\'' + hexline + '\'')
    if(i == 16):  #change number of grouping here       
        print('b\'' + hexline + '\'')
        i=0
        hexline = ''
        groupCount += 1

    hexline += '\\x' + hex
    i+=1         
    lenCount += 1

This should now give us the format we can just cut and paste from the output window into our code for the Icon data. For every 16th hex value, a new line is created with b’ at the beginning of the line to represent byte code representation using string. Again I truncated the data to save space.

b'\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x00\x00\x00\x00h\x04\x00'
b'\x16\x00\x00\x00(\x00\x00\x00\x10\x00\x00\x00 \x00\x00\x00\x01\x00 '
...
b'\x00\x00\xc0\x01\x00\x00\x80\x01\x00\x00\x00\x07\x00\x00\x00\x07'
b'\x00\x00\x01\x00\x00\xc0\x01\x00\x00\xc0\x01\x00\x00\xc0\x01\x00'

Now we’ll do an example of a TKInter window with the embedded icon data. Use the full icon data from the output generated by the code. The data shown in the code below is truncated in this code example.

import tkinter
import tempfile

ICON = (b'\x00\x00\x01\x00\x01\x00\x10\x10\x00\x00\x00\x00\x00\x00h\x04\x00'
b'\x16\x00\x00\x00(\x00\x00\x00\x10\x00\x00\x00 \x00\x00\x00\x01\x00 '
...
b'\x00\x00\xc0\x01\x00\x00\x80\x01\x00\x00\x00\x07\x00\x00\x00\x07'
b'\x00\x00\x01\x00\x00\xc0\x01\x00\x00\xc0\x01\x00\x00\xc0\x01\x00')

_, ICON_PATH = tempfile.mkstemp()
with open(ICON_PATH, 'wb') as icon_file:
    icon_file.write(ICON)

root = tk.Tk()
root.iconbitmap(default=ICON_PATH)

tk.mainloop()

If you cut and paste the data value into the ICON correctly, you should see a blank tk window with the icon that had the generated the data.

Here are the complete codes for the data generator and the tk example. You need to rename the file extension to .py. This server doesn’t allow .py extension to be viewed.

IconData.txt
Tkinter_IconData_example.txt