Reputation: 777
Is there any way to get a tkinter.PhotoImage
object from a tkinter.Label
instance? I know there's this question, which has a partially satisfying answer, but I really need to get a PhotoImage
object:
>>> import tkinter as tk
>>>
>>> root = tk.Tk()
>>>
>>> image1 = tk.PhotoImage(file="img.gif")
>>> image2 = tk.PhotoImage(file="img.gif")
>>>
>>> label = tk.Label(root, image=image1)
>>> label._image_ref = image1
>>> label.cget("image") == image2
False
Is there perhaps a function which allows me to get an image object from a pyimage
string? I.e. one obtained from label.cget("image")
?
The answer is, apparantly, you can't. The closest you can get to doing this is getting the image source (file or data) and checking (probably by hashing) whether or not the two images are the same. tkinter.PhotoImage
does not implement an __eq__
, so you can't just compare two images for equal data. Here's a final example which solves the problem (mostly):
import hashlib
import os
import tkinter as tk
_BUFFER_SIZE = 65536
def _read_buffered(filename):
"""Read bytes from a file, in chunks.
Arguments:
- filename: str: The name of the file to read from.
Returns:
- bytes: The file's contents.
"""
contents = []
with open(filename, "rb") as fd:
while True:
chunk = fd.read(_BUFFER_SIZE)
if not chunk:
break
contents.append(chunk)
return bytes().join(contents)
def displays_image(image_file, widget):
"""Check whether or not 'widget' displays 'image_file'.
Reading an entire image from a file is computationally expensive!
Note that this function will always return False if 'widget' is not mapped.
This doesn't work for images that were initialized from bytes.
Arguments:
- image_file: str: The path to an image file.
- widget: tk.Widget: A tkinter widget capable of displaying images.
Returns:
- bool: True if the image is being displayed, else False.
"""
expected_hash = hashlib.sha256(_read_buffered(image_file)).hexdigest()
if widget.winfo_ismapped():
widget_file = widget.winfo_toplevel().call(
widget.cget("image"), "cget", "-file"
)
if os.path.getsize(widget_file) != os.path.getsize(image_file):
# Size differs, the contents can never be the same.
return False
image_hash = hashlib.sha256(
_read_buffered(widget_file)
).hexdigest()
return image_hash == expected_hash
Upvotes: 4
Views: 5067
Reputation: 4482
As a tkinter
is a wrapper over tk
, so does PhotoImage
in same fashion is a wrapper over image
. And it's clear that you can't just move backwards and create a PhotoImage
, from that image
.
But still, because you can execute tk commands and both PhotoImage
and image
have similar structure, your best bet would be something like this:
import tkinter as tk
root = tk.Tk()
image1 = tk.PhotoImage(file="img.gif")
image2 = tk.PhotoImage(file="img.gif")
label = tk.Label(root, image=image1)
label._image_ref = image1
foo = root.call(label.cget('image'), 'cget', '-file')
bar = image2['file']
print('1st image:\t%s\n2nd image:\t%s\nEqual:\t%r' % (foo, bar, foo == bar))
Upvotes: 1