Recipe 11.6. Embedding Inline GIFs Using Tkinter
Credit: Brent Burley
Problem
You need
to embed GIF images inside your source codefor use in Tkinter
buttons, labels, and so onto make toolbars and the like
without worrying about installing the right icon files.
Solution
A lively Tkinter GUI can include many small images. However, you
don't want to require that a small GIF file be
present for each of these images. Ensuring the presence of many small
files is a bother, and if they're missing, your GUI
may be unusable. Fortunately, you can construct Tkinter
PhotoImage objects with inline data.
It's easy to convert a GIF to inline form as Python
source code, with a little script or snippet that you can save and
run separately.
import base64This emits to standard output a lot of strange-looking
print "icon='''\\\n" + base64.encodestring
(open("icon.gif").read( )) + "'''"
"text", which you can capture
(typically using your shell's facilities for output
redirection, or with copy and paste) and split into lines of
reasonable length:
icon=Now, you can use this Python-inlined data in Tkinter:
'''R0lGODdhFQAVAPMAAAQ2PESapISCBASCBMTCxPxmNCQiJJya/ISChGRmzPz+/PxmzDQyZ
DQyZDQyZDQyZCwAAAAAFQAVAAAElJDISau9Vh2WMD0gqHHel
JwnsXVloqDd2hrMm8pYYiSHYfMMRm
53ULlQHGFFx1MZCciUiVOsPmEkKNVp3UBhJ4Ohy1
UxerSgJGZMMBbcBACQlVhRiHvaUsXHgywTdyc
LdxyB gm1vcTyIZW4MeU6NgQEBXEGRcQcIlwQIAwEHoioCAgWmCZ0Iq5+
hA6wIpqislgGhthEAOw==
'''
import Tkinter
if _ _name_ _ == '_ _main_ _':
root = Tkinter.Tk( )
iconImage = Tkinter.PhotoImage(master=root, data=icon)
Tkinter.Button(image=iconImage).pack( )
Discussion
The basic technique is to encode the GIF with the standard Python
module base64 and store the results as a string
literal in the Python code. At runtime, the Python code passes that
string object to Tkinter's
PhotoImage. The current release of
PhotoImage supports GIF and PPM, but inline data
is supported only for GIF. To convert between image formats, see
Recipe 11.7. Of course, you
can use file='filename', instead of
data=string, for either GIF or
PPM, if your image data is indeed in a file.You must keep a reference to the PhotoImage object
yourself; that reference is not kept by the Tkinter widget. If you
pass the object to Button and forget it, you will
become frustrated! Here's an easy workaround for
this minor annoyance:
def makeImageWidget(icondata, *args, **kwds):Using this handy makeImageWidget function, the
if args:
klass = args.pop(0)
else:
klass = Tkinter.Button
class Widget(klass):
def _ _init_ _(self, image, *args, **kwds):
kwds['image'] = image
klass._ _init_ _(self, *args, **kwds)
self._ _image = image
return Widget(Tkinter.PhotoImage(data=icondata), *args, **kwds)
equivalent of the example in the recipe becomes:
makeImageWidget(icon).pack( )The master argument on PhotoImage
is optional; it defaults to the default application window. If you
create a new application window (by calling Tk
again), you must create your images in that context and supply the
master argument, so the makeImageWidget function has
to be updated to let you optionally pass the master argument to the
PhotoImage constructor. However, most applications
do not require this refinement.
See Also
Information about Tkinter can be obtained from a variety of sources,
such as Fredrik Lundh, An Introduction to
Tkinter (PythonWare: http://www.pythonware.com/library), New
Mexico Tech's Tkinter
Reference (http://www.nmt.edu/tcc/help/lang/python/docsl),
Python in a Nutshell, and various other books.