Show images and icons#
To show a picture in tkinter you wrap it in an image object and hand that to a
widget’s image= option. There are two image classes, and one notorious
gotcha to know before anything else.
Which image class#
ttk.PhotoImage— tkinter’s built-in image. It reads GIF, PNG, PGM, and PPM files (and base64-encoded GIF/PNG data), and needs no extra library.Pillow’s
ImageTk.PhotoImage— reads every common format (JPEG, BMP, TIFF, WebP, …) and lets you resize, crop, and filter first. Pillow is already a dependency of ttkbootstrap, so it is always available.
Reach for Pillow for anything beyond a simple GIF/PNG — which is most real work.
Keep a reference (the image that vanishes)#
Important
An image object must be kept alive by your own code, or it disappears.
Tk stores the image by name, and a widget’s image= option does not hold
the Python object — so if the only reference is a local variable, the garbage
collector reclaims the image the moment the function returns and the widget
goes blank.
This is the single most common tkinter image bug. It applies to both image
classes. The fix is to keep a reference somewhere that outlives the function —
conventionally on the widget itself, or on self:
def add_logo(parent):
photo = ttk.PhotoImage(file="logo.png")
label = ttk.Label(parent, image=photo)
label.image = photo # <- keeps the image alive with the label
label.pack()
Without the label.image = photo line, the label shows nothing. When you store
images on self (say in a class-based app), the same rule holds — just make
sure the attribute lives as long as the widget does.
Displaying an image#
Pass the image as image=. To show it alongside text, add compound= to
say where the image sits relative to the label:
ttk.Button(app, text="Open", image=photo, compound="left")
compound takes "left", "right", "top", "bottom" (the image on
that side of the text), "center" (text over image), "image" (image only),
"text" (text only), or "none" (the image if there is one, otherwise the
text).
Loading and resizing with Pillow#
Open with Pillow, transform, then wrap the result. Keep a reference as always:
from PIL import Image, ImageTk
pil = Image.open("photo.jpg")
pil = pil.resize((120, 120))
thumb = ImageTk.PhotoImage(pil)
card = ttk.Label(app, image=thumb)
card.image = thumb
card.pack()
Embedding an image in your code#
To ship an image inside a .py file with no separate asset, base64-encode it
and pass it as data= to ttk.PhotoImage (GIF/PNG only):
LOGO = "iVBORw0KGgo..." # base64 string of a PNG
photo = ttk.PhotoImage(data=LOGO)
Themed glyph icons#
For icons — the small symbols on buttons and menu items — you usually want a
crisp, theme-following glyph rather than a raster file. ttkbootstrap renders
those from a built-in Bootstrap Icons font. Just pass icon= — no image object
to build or keep alive, and the glyph recolors with the theme and widget state:
ttk.Button(app, text="Settings", icon="gear-fill")
See the Icons guide for the full icon API, and Windows for setting the application icon.
A worked example#
Loads a Pillow image, scales it, and displays it — with the reference kept so it stays on screen:
import ttkbootstrap as ttk
from PIL import Image, ImageTk
app = ttk.App(title="Image")
pil = Image.open("photo.jpg").resize((200, 200))
photo = ImageTk.PhotoImage(pil)
label = ttk.Label(app, image=photo, padding=10)
label.image = photo # keep the reference
label.pack()
app.mainloop()
See also
Animate a GIF — swapping frames on a timer.
Set the app icon — the titlebar and taskbar icon.
Icons guide — glyph names, sizing, and per-state icons.
The Pillow documentation — raster formats and image manipulation.
Reference#
Imaging — the full
PhotoImageAPI.