0

I am working on a python program that displays a series of images using Tkinter and ImageTk. I have not been able to display more than a single image. Below is a small complete program that reproduces the error. The program searches the current directly recursively for jpg files, and displays them as the uses presses Enter.

import Tkinter, ImageTk,os, re


def ls_rec(direc):
    try:
        ls = os.listdir(direc)
    except Exception as e:
        return
    for f in os.listdir(direc):
        fpath = os.path.join(direc, f)
        if os.path.isfile(fpath):
            yield fpath
        elif os.path.isdir(fpath):
            for f2 in iterate_dir(os.path.join(direc,f)):
                yield f2

images = filter(lambda a:re.match('.*\\.jpg$',a),ls_rec(os.getcwd()))
assert(len(images)>10)
top = Tkinter.Tk()
image_label = Tkinter.Label(top)
Label_text = Tkinter.Label(top,text="Below is an image")
img = None
i = 0



def get_next_image(event = None):
    global i, img
    i+=1
    img = ImageTk.PhotoImage(images[i])
    label.config(image=img)
    label.image = img

top.bind('<Enter>',get_next_image)
label.pack(side='bottom')
Label_text.pack(side='top')
get_next_image()
top.mainloop()

The program fails with the following traceback:

Traceback (most recent call last):
  File "/usr/lib/python2.7/pdb.py", line 1314, in main
    pdb._runscript(mainpyfile)
  File "/usr/lib/python2.7/pdb.py", line 1233, in _runscript
    self.run(statement)
  File "/usr/lib/python2.7/bdb.py", line 387, in run
    exec cmd in globals, locals
  File "<string>", line 1, in <module>
  File "/home/myuser/Projects/sample_images.py", line 1, in <module>
    import Tkinter, ImageTk,os, re
  File "/home/myuser/Projects/sample_images.py", line 32, in get_next_image
    img = ImageTk.PhotoImage(some_image[1])
  File "/usr/lib/python2.7/dist-packages/PIL/ImageTk.py", line 109, in __init__
    mode = Image.getmodebase(mode)
  File "/usr/lib/python2.7/dist-packages/PIL/Image.py", line 245, in getmodebase
    return ImageMode.getmode(mode).basemode
  File "/usr/lib/python2.7/dist-packages/PIL/ImageMode.py", line 50, in getmode
    return _modes[mode]
KeyError: '/home/myuser/sampleimage.jpg'

Does anyone get the same behavior when running this code? What am I doing wrong?

EDIT: Using korylprince's solution, and a bit of cleaning, the following is a working version of the original code:

import os, re, Tkinter, ImageTk

def ls_rec(direc, filter_fun=lambda a:True):
    for (dirname, dirnames, fnames) in os.walk(direc):
        for fname in fnames:
            if filter_fun(fname):
                yield os.path.join(dirname,fname)


top = Tkinter.Tk()
image_label = Tkinter.Label(top)
text_label = Tkinter.Label(top,text="Below is an image")
images = ls_rec(os.getcwd(), lambda a:re.match('.*\\.jpg$',a))

imgL = []

def get_next_image(event = None):
    fname = images.next()
    print fname
    fhandle = open(fname)
    img = ImageTk.PhotoImage(file=fhandle)
    fhandle.close()
    imgL.append(img)
    image_label.config(image=img)


top.bind('<Return>',get_next_image)
image_label.pack(side='bottom')
text_label.pack(side='top')
get_next_image()
top.mainloop()

Edit: top.bind('<Enter>'...) actually bound the event of the mouse entering the frame, rather than user pressing Enter key. The correct line is top.bind('<Return>',...).

3
  • Is there a reason you aren't using glob()? Commented Jun 9, 2013 at 4:17
  • No. I just knew about os.walk. I have this ls_rec implemented in my personal library, so it doesn't bother me. But yeah, glob is simpler. Commented Jun 9, 2013 at 5:06
  • Actually, glob is not recursive. So there is after all a reason. Commented Jun 9, 2013 at 5:18

1 Answer 1

3

ImageTk.PhotoImage is not really documented properly.

You should try something like this:

#outside of functions
images = list()

#inside function
global images
with open(images[i]) as f:
    img = ImageTk.PhotoImage(file=f)
    images.append(img)

The reason for putting the image in the list is so that python will have a reference to it. Otherwise the garbage collector will delete the image object eventually.

Sign up to request clarification or add additional context in comments.

6 Comments

I concur. I have wasted a lot of time thanks to this module. I tried your solution, which did eliminate the original error. I now run into the other error that I have been also seeing frequently: TclError: image "pyimage10" doesn't exist I have searched for this error. Some claim it has to do with PhotoImages being garbage collected when not enough references exist to them. But I seem to have already addressed that possible issue. What now? Any idea of why "image "pyimage10" doesn't exist"? Also, do you know if it is possible to close the file after img has been instantiated?
I just updated my answer. Basically you have to keep some reference open in the image object or it will get deleted. Since you keep rebinding img, the images get deleted.
Your solution worked! I had tried putting the images in lists, in a global variable, and so on. It seems that I had two errors at once, and I never fixed both at the same time. Thank you
One final thing: Do you know when I am able to close the file?
Using the with statement opens the file in a context manager. Basically this means the file is closed after the with statement block is done (that's what the context manager does for a file). I am guessing PhotoImage loads the file into memory.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.