Pillow raises error: "AttributeError: read" when attempting to use Image.Open for ImageTk

Question:

I am attempting to create a paint program but in my open() function, it raises this error:

Exception in Tkinter callback
Traceback (most recent call last):
  File "C:Program FilesWindowsAppsPythonSoftwareFoundation.Python.3.10_3.10.2288.0_x64__qbz5n2kfra8p0libtkinter__init__.py", line 1921, in __call__
    return self.func(*args)
  File "C:Users-------PycharmProjectsPaintmain.py", line 31, in open
    canvas.create_image(0, 0, anchor=NW, image=PIL.ImageTk.PhotoImage(file=Image.open("C:\Users\Anthony\Pictures\dddddd.png")))
  File "C:Users-------PycharmProjectsPaintvenvlibsite-packagesPILImageTk.py", line 103, in __init__
    image = _get_image_from_kw(kw)
  File "C:Users-------PycharmProjectsPaintvenvlibsite-packagesPILImageTk.py", line 59, in _get_image_from_kw
    return Image.open(source)
  File "C:Users-------PycharmProjectsPaintvenvlibsite-packagesPILImage.py", line 3140, in open
    prefix = fp.read(16)
  File "C:Users-------PycharmProjectsPaintvenvlibsite-packagesPILImage.py", line 517, in __getattr__
    raise AttributeError(name)
AttributeError: read
Exception ignored in: <function PhotoImage.__del__ at 0x000002177C9E93F0>
Traceback (most recent call last):
  File "C:Users-------PycharmProjectsPaintvenvlibsite-packagesPILImageTk.py", line 133, in __del__
    name = self.__photo.name
AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'

Here is code relevant to the error:

def open():
    path = filedialog.askopenfile(mode="r", filetypes=[("PNG Image", "*.png")], defaultextension="*.*")
    width, height = Image.open(path.name, mode="r").size
    canvas.config(width=width, height=height)
    canvas.create_image(0, 0, anchor=NW, image=PIL.ImageTk.PhotoImage(file=Image.open(path.name)))

I replaced the "path.name" with a normal path thinking that it may be filedailog.askopenfile isn’t providing a proper path although it didn’t work. I did double slashes as well, just in case it was using something like "n".

Asked By: AntXD

||

Answers:

file option of ImageTk.PhotoImage() should be a file name or file object, not instance of Image.

Also you need to keep the reference of the image, otherwise it will be garbage collected after exiting the function.

It is better to use askopenfilename() if you just want a filename. And you have called Image.open() twice.

Below is the modified open():

def open():
    # use askopenfilename() instead
    path = filedialog.askopenfilename(filetypes=[("PNG Image", "*.png")],
                                      defaultextension=".png")
    if path:
        image = Image.open(path)
        width, height = image.size
        tkimg = ImageTk.PhotoImage(image)
        canvas.config(width=width, height=height)
        canvas.create_image(0, 0, anchor=NW, image=tkimg)
        canvas.image = tkimg # save the reference of image to avoid garbage collection

Note also that open() is a built-in function of Python, it is better not to use it as your function name.

Answered By: acw1668