Bartłomiej 'furas' Burek
furas.pl
# prywatne notatki - Python, Linux, Machine Learning, etc.

Tkinter: How to load, display and replace image on Label, Button or Canvas

Images

Few images used in examples

python python python

Reading image

Tkinter uses PhotoImage to read PNG, GIF, PGM/PPM.

Older version didn't read PNG. All version still can't read JPG or other formats.

img = tk.PhotoImage(file="smile-1.png")

It has to use named variable file=. It can't skip this name.

It may also use named variable data= to use base64-encoded string with PNG or GIF data.

img = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEX///8AAABVwtN+AAAAJ0lEQVQI12P4DwQPGCDkAQYGhgRSSDv+BjwkqabZ/2/AQ+LVi+QLAGveQwjt4H11AAAAAElFTkSuQmCC")

At the end of page you can see how to convert file with image PNG or GIF

To read JPG you have to use module pillow

from PIL import ImageTk

img = ImageTk.PhotoImage(file="image.jpg")

or

from PIL import ImageTk, Image

img = ImageTk.PhotoImage(Image.open("image.jpg"))
# or
img = ImageTk.PhotoImage(image=Image.open("image.jpg"))

or

from PIL import ImageTk, Image

img = ImageTk.PhotoImage(date=open("image.jpg").read())

Image can be also used to modify image before displaying - ie. resize, crop, rotate, flip, convert to grayscale, etc.

from PIL import ImageTk, Image

image = Image.open("image.jpg")
image = image.resize((200,100)
img = ImageTk.PhotoImage(image)

More functions to modify image in pillow

In tk.PhotoImage (but not in ImageTk.PhotoImage) you can change image using

img['data'] = "iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEUAAADw0gCjrW2CAAAAI0lEQVQI12NgQAL2////byCFPPihHg9JqmkHGOrxkHj1IgEAZH9nDhQLxPMAAAAASUVORK5CYII="
# or
img.config(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEUAAADw0gCjrW2CAAAAI0lEQVQI12NgQAL2////byCFPPihHg9JqmkHGOrxkHj1IgEAZH9nDhQLxPMAAAAASUVORK5CYII=")

or

img['file'] = "image.png"
# or
img.config(file="image.png")

You can also check values

print(img['file'])
print(img['data'])
# or
print(img.cget('file'))
print(img.cget('data'))

In tk.PhotoImage you can put one image on another. If both have the same size then one image replace other image. If you paste smaller image then you will see partially old image.

img.paste(Image.open("image.jpg"))

Displaying with Label

Now it can be displayed with tk.Label(..., image=...)

import tkinter as tk

root = tk.Tk()

img = tk.PhotoImage(file="smile-1.png")

label = tk.Label(root, image=img)
label.pack()

root.mainloop()
tkinter-image-label

The same with base64 string

import tkinter as tk

root = tk.Tk()

img = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEX///8AAABVwtN+AAAAJ0lEQVQI12P4DwQPGCDkAQYGhgRSSDv+BjwkqabZ/2/AQ+LVi+QLAGveQwjt4H11AAAAAElFTkSuQmCC")

label = tk.Label(root, image=img)
label.pack()

root.mainloop()

The same with pillow.

Image can be used before tk.Tk() (or after tk.Tk()) but PhotoImage() has to be used only after tk.Tk()

import tkinter as tk
from PIL import ImageTk, Image

image = Image.open("image.jpg")
image = image.resize((200,100)

root = tk.Tk()

img = ImageTk.PhotoImage(image)

label = tk.Label(root, image=img)
label.pack()

root.mainloop()

To display more images

import tkinter as tk

root = tk.Tk()

img = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEX///8AAABVwtN+AAAAJ0lEQVQI12P4DwQPGCDkAQYGhgRSSDv+BjwkqabZ/2/AQ+LVi+QLAGveQwjt4H11AAAAAElFTkSuQmCC")

for y in range(3):
    for x in range(3):
        label = tk.Label(root, image=img)
        label.grid(row=y, column=x)

root.mainloop()
tkinter-image-label

To change image in Label you can create new PhotoImage

label['image'] = ImageTk.PhotoImage(image)
#or
label.config(image=ImageTk.PhotoImage(image))

You can also use existing PhotoImage

img = ImageTk.PhotoImage(image)

# later 

label['image'] = img
# or
label.config(image=img)

You can also replace data in PhotImage like in "Reading image"


Displaying with Button

To display with tk.Button(..., image=...)

import tkinter as tk

# --- functions ---    

def on_click():
    print('clicked')

# --- main ---

root = tk.Tk()

img = tk.PhotoImage(file="smile-1.png")

button = tk.Button(root, image=img, command=on_click)
button.pack()

root.mainloop()
tkinter-image-button

The same with base64 string

import tkinter as tk

# --- functions ---    

def on_click():
    print('clicked')

# --- main ---

root = tk.Tk()

img = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEX///8AAABVwtN+AAAAJ0lEQVQI12P4DwQPGCDkAQYGhgRSSDv+BjwkqabZ/2/AQ+LVi+QLAGveQwjt4H11AAAAAElFTkSuQmCC")

button = tk.Button(root, image=img, command=on_click)
button.pack()

root.mainloop()

To display more images

import tkinter as tk

# --- functions ---    

def on_click():
    print('clicked')

# --- main ---

root = tk.Tk()

img = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEX///8AAABVwtN+AAAAJ0lEQVQI12P4DwQPGCDkAQYGhgRSSDv+BjwkqabZ/2/AQ+LVi+QLAGveQwjt4H11AAAAAElFTkSuQmCC")

for y in range(3):
    for x in range(3):
        button = tk.Button(root, image=img, command=on_click)
        button.grid(row=y, column=x)

root.mainloop()
tkinter-image-button

To change image in Button you can do

button['image'] = ImageTk.PhotoImage(image)

or

button.config(image=ImageTk.PhotoImage(image))

In this example I has to button['command'] to use button as argument in function.

In this example I has to button['command'] to use button as argument in function.

import tkinter as tk

# --- functions ---    

def on_click(widget):
    print('clicked')
    widget['image'] = img2

# --- main ---

root = tk.Tk()

img1 = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEX///8AAABVwtN+AAAAJ0lEQVQI12P4DwQPGCDkAQYGhgRSSDv+BjwkqabZ/2/AQ+LVi+QLAGveQwjt4H11AAAAAElFTkSuQmCC")
img2 = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEUAAADw0gCjrW2CAAAAI0lEQVQI12NgQAL2////byCFPPihHg9JqmkHGOrxkHj1IgEAZH9nDhQLxPMAAAAASUVORK5CYII=")

for y in range(3):
    for x in range(3):
        button = tk.Button(root, image=img1)
        button['command'] = lambda arg=button:on_click(arg)
        button.grid(row=y, column=x)

root.mainloop()

To change image in Button you can create new PhotoImage

button['image'] = ImageTk.PhotoImage(image)
#or
button.config(image=ImageTk.PhotoImage(image))

You can also use existing PhotoImage

img = ImageTk.PhotoImage(image)

# later 

button['image'] = img
# or
button.config(image=img)

You can also replace data in PhotImage like in "Reading image"


Displaying with Canvas

To display on Canvas you have to use canvas.create_image((x,y), image=...), not pack()/grid()/place().

item_id = canvas.create_image((0,0), image=img)

It returns object's ID which later you can use to access this image (and move, remove, replace, etc.).

If you will not modify image then you don't have to assign to variable.

import tkinter as tk

root = tk.Tk()

img = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEUAAADw0gCjrW2CAAAAI0lEQVQI12NgQAL2////byCFPPihHg9JqmkHGOrxkHj1IgEAZH9nDhQLxPMAAAAASUVORK5CYII=")

canvas = tk.Canvas(root)
canvas.pack()

canvas.create_image((0, 0), image=img)

root.mainloop()
tkinter-image-canvas

Image uses center point as anchor so image on screenshot above is visible only partially because center of image is in position (0, 0). To put top, left corner of image in position (0, 0) you have to use anchor='nw' ('nw' means North West, top left).

item_id = canvas.create_image((0,0), image=img, anchor='nw')
import tkinter as tk

root = tk.Tk()

img = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEUAAADw0gCjrW2CAAAAI0lEQVQI12NgQAL2////byCFPPihHg9JqmkHGOrxkHj1IgEAZH9nDhQLxPMAAAAASUVORK5CYII=")

canvas = tk.Canvas(root)
canvas.pack()

canvas.create_image((0, 0), image=img)

root.mainloop()
tkinter-image-canvas

Anchor 'nw' (and center point) is the most popular but you can also use other values 'ne' (North East, top right), 'se' (South East, bottom right), 'sw' (South West, bottom left),

This example uses different anchors to easily put images in corners. Image has size (300, 300) and images can use values 0 and 300

import tkinter as tk

root = tk.Tk()

img = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEX///8AAABVwtN+AAAAJ0lEQVQI12P4DwQPGCDkAQYGhgRSSDv+BjwkqabZ/2/AQ+LVi+QLAGveQwjt4H11AAAAAElFTkSuQmCC")

canvas = tk.Canvas(root, width=200, height=200)
canvas.pack()

canvas.create_image((100, 100), image=img)  # center 

canvas.create_image((0, 0), image=img, anchor='nw')      # top, left corner
canvas.create_image((200, 0), image=img, anchor='ne')    # top, right corner
canvas.create_image((200, 200), image=img, anchor='se')  # bottom, right corner
canvas.create_image((0, 200), image=img, anchor='sw')    # bottom, left corner

root.mainloop()
tkinter-image-canvas

To change image in Canvas you have to use canvas.itemconfig() with object_id or tag

canvas.itemconfig(object_id, image=ImageTk.PhotoImage(image))

# or 

img = ImageTk.PhotoImage(image)
# later 
canvas.itemconfig(object_id, image=img)

This example uses object ID to change image

import tkinter as tk

# --- functions ---

def on_click():
    canvas.itemconfig(img_id, image=img2)

# --- main ---

root = tk.Tk()

img1 = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEX///8AAABVwtN+AAAAJ0lEQVQI12P4DwQPGCDkAQYGhgRSSDv+BjwkqabZ/2/AQ+LVi+QLAGveQwjt4H11AAAAAElFTkSuQmCC")
img2 = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEUAAADw0gCjrW2CAAAAI0lEQVQI12NgQAL2////byCFPPihHg9JqmkHGOrxkHj1IgEAZH9nDhQLxPMAAAAASUVORK5CYII=")

canvas = tk.Canvas(root, width=200, height=200)
canvas.pack()

img_id = canvas.create_image((100, 100), image=img1)  # center 

button = tk.Button(root, text='CHANGE', command=on_click)
button.pack()

root.mainloop()

This example create three image with the same tag "smile" and later it uses tag "smile" to replace PhotoImage in all images.

import tkinter as tk

# --- functions ---

def on_click():
    canvas.itemconfig("smile", image=img2)

# --- main ---

root = tk.Tk()

img1 = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEX///8AAABVwtN+AAAAJ0lEQVQI12P4DwQPGCDkAQYGhgRSSDv+BjwkqabZ/2/AQ+LVi+QLAGveQwjt4H11AAAAAElFTkSuQmCC")
img2 = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEUAAADw0gCjrW2CAAAAI0lEQVQI12NgQAL2////byCFPPihHg9JqmkHGOrxkHj1IgEAZH9nDhQLxPMAAAAASUVORK5CYII=")

canvas = tk.Canvas(root, width=200, height=200)
canvas.pack()

canvas.create_image((50, 100), image=img1, tag="smile")
canvas.create_image((100, 100), image=img1, tag="smile")  # center 
canvas.create_image((150, 100), image=img1, tag="smile")

button = tk.Button(root, text='CHANGE', command=on_click)
button.pack()

root.mainloop()

You can also replace data in PhotoImage like in "Reading image". It will change data in all images which use the same PhotoImage.

import tkinter as tk

# --- functions ---

def on_click():
    img['data'] = "iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEUAAADw0gCjrW2CAAAAI0lEQVQI12NgQAL2////byCFPPihHg9JqmkHGOrxkHj1IgEAZH9nDhQLxPMAAAAASUVORK5CYII="

# --- main ---

root = tk.Tk()

img = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEX///8AAABVwtN+AAAAJ0lEQVQI12P4DwQPGCDkAQYGhgRSSDv+BjwkqabZ/2/AQ+LVi+QLAGveQwjt4H11AAAAAElFTkSuQmCC")

canvas = tk.Canvas(root, width=200, height=200)
canvas.pack()

canvas.create_image((50, 100), image=img)
canvas.create_image((100, 100), image=img)  # center 
canvas.create_image((150, 100), image=img)

button = tk.Button(root, text='CHANGE', command=on_click)
button.pack()

root.mainloop()

Creating base64 string

To create base64 string you have to - read PNG or GIF in bytes mode rb - convert to base64 to get it as bytes - convert bytes to string

fh = open('smile.png', 'rb')  # open in `bytes` mode
data = fh.read()  # read all
data = base64.b64encode(data)  # create byte64 `bytes`
data = data.decode()  # convert `bytes` to `string`

or shorter

data = base64.b64encode(open('smile.png', 'rb').read()).decode()

Bug in PhotoImage

There is bug in PhotoImage which removes image from memory (so it is not displayed) when it is assigned to local variable created in function or class method.

It has to be assigned to global variable

def function():
    global img

    img = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEX///8AAABVwtN+AAAAJ0lEQVQI12P4DwQPGCDkAQYGhgRSSDv+BjwkqabZ/2/AQ+LVi+QLAGveQwjt4H11AAAAAElFTkSuQmCC")

or class variable

def function():
    img = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEX///8AAABVwtN+AAAAJ0lEQVQI12P4DwQPGCDkAQYGhgRSSDv+BjwkqabZ/2/AQ+LVi+QLAGveQwjt4H11AAAAAElFTkSuQmCC")

    label = tk.Label(image=img)
    label.image = img  # keep reference (it can be different name - ie. `label.img`)

    label.pack()

or using self. in class

class MyClass:

    def method(self):
        self.img = tk.PhotoImage(data="iVBORw0KGgoAAAANSUhEUgAAACMAAAAjAQMAAAAkFyEaAAAABlBMVEX///8AAABVwtN+AAAAJ0lEQVQI12P4DwQPGCDkAQYGhgRSSDv+BjwkqabZ/2/AQ+LVi+QLAGveQwjt4H11AAAAAElFTkSuQmCC")

Links

Książki: python-dla-kazdego-podstawy-programowania python-wprowadzenie python-leksykon-kieszonkowy python-receptury python-programuj-szybko-i-wydajnie python-projekty-do-wykorzystania black-hat-python-jezyk-python-dla-hackerow-i-pentesterow efektywny-python-59-sposobow-na-lepszy-kod tdd-w-praktyce-niezawodny-kod-w-jezyku-python aplikacje-internetowe-z-django-najlepsze-receptury