【问题标题】:Getting a PhotoImage object from a tkinter label从 tkinter 标签获取 PhotoImage 对象
【发布时间】:2017-12-07 10:27:24
【问题描述】:

有没有办法从tkinter.Label 实例中获取tkinter.PhotoImage 对象?我知道有this question,它有一个部分令人满意的答案,但我真的需要一个PhotoImage 对象:

>>> 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

是否有一个函数可以让我从pyimage 字符串中获取图像对象? IE。一个从label.cget("image")获得?


答案是,apparantly,你不能。最接近的方法是获取图像源(文件或数据)并检查(可能通过散列)两个图像是否相同。 tkinter.PhotoImage没有实现__eq__,所以你不能只比较两个图像以获得相同的数据。这是解决问题的最后一个示例(大部分):

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

【问题讨论】:

  • 您将其存储为label._image_ref,不是吗?因此链接的答案适用于label._image_ref.cget('file')。但是为什么你声称它是部分令人满意的呢?在您的情况下,平等始终是False,因为它与image1 == image2 相同(PhotoImage 没有__eq__ 方法)。
  • 我正在编写一个模拟 GUI 测试库,我想要一种方法来检查当前是否正在显示图像。我不能假设人们会保留对图像的引用。我不明白为什么 PhotoImage __eq__ 实现不处理视觉相似性,但这是一个不同的问题。
  • PhotoImage 对象没有定义__eq__ 方法,所以它们继承了默认的方法,这意味着做image1 == image2 相当于image1 is image2,所以它会返回False,因为它们不是同一个对象,即使它们包含相同的图像数据。
  • 嗯,这很荒谬,但我可以希望解决这个问题。
  • @Coal_,还有> I can't assume people will keep a reference to the image.。为什么你不能?我可能是错的,但这是必须的,因为任何人都应该保留参考。

标签: python image user-interface tkinter


【解决方案1】:

tkintertk 的包装器,PhotoImage 也是 image 的包装器。很明显,您不能只是向后移动并从 image 创建一个 PhotoImage

但是,由于您可以执行 tk 命令,并且 PhotoImageimage 具有相似的结构,因此您最好的选择是这样的:

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))

【讨论】:

  • 我知道你来自哪里。如果我要这样实现它,我可能会打开文件并对数据进行哈希处理以确保它们的内容相同。再说一次,这是一个非常脆弱的解决方案(特别是因为 PhotoImage 也可以从图像字节初始化)。如果我找不到更好的解决方案,我会选择这个。谢谢。
  • @Coal_,这不是问题,因为它是一个包装器,所以image 也可以以这种方式初始化。如果它来自字节,则检查 data 是否相等!此外,您可以即时确定它是从哪个源初始化的!
  • @Coal_,但是,相同的文件可以通过不同的路径初始化,如果是这样的话 - 这是一个问题。但是正如@PM 2Ring 提到的那样 tkinter isn't an image processing library ,所以在这种情况下,即使你有一对 PhotoImages 或一对 images,你也无能为力。
  • 你能给我指出一些关于root.call 或至少-file 标志的文档吗?我似乎在任何地方都找不到。
  • @Coal_,当然,call 很好地描述了here。而-file 是一个选项,就像image2['file'] 一样。按照我的回答中的第二个链接(或使用shortcut)。
猜你喜欢
  • 1970-01-01
  • 2023-02-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多