【问题标题】:How to get smooth edges with png image in tkinter label如何在 tkinter 标签中使用 png 图像获得平滑边缘
【发布时间】:2019-07-15 07:12:23
【问题描述】:

当我将具有透明背景的 png 图像作为标签放置在 tkinter 画布上时,边缘会出现波纹。我怎样才能得到光滑的边缘?看两个例子:

我有以下代码:

import tkinter as tk # Python 3
master = tk.Tk()
master.minsize(500, 500)
master.geometry("500x500")
master.overrideredirect(True)
master.lift()
master.wm_attributes("-topmost", True)
master.wm_attributes("-transparentcolor", "white")
master.configure(background='white')

img = tk.PhotoImage(file="c:/temp/co.png")
panel = tk.Label(master, image = img, text="2", bg="white", compound=tk.CENTER, fg="#EFEFEF", font=("Helvetica", 14))
panel.place(x=300, y=200)

tk.mainloop()

这个想法是在 Windows 桌面顶部有一个透明层,上面放置包含 png 图像的小部件。

编辑: Aivaras Kazakevičius 的回答如下:

要玩的原始图像是:

【问题讨论】:

  • 您需要修改图像,将圆圈周围的像素更改为白色。
  • 感谢您的评论。但这不是正确的解决方案。圆圈周围的像素是半透明的,从而产生平滑的边缘。将这些 bij 替换为白色会使圆圈更加细化。

标签: python-3.x tkinter png


【解决方案1】:

编辑#1

我已经确认问题是由于图像的预乘而出现的。本来以为是透明图片周围的白色边框被画出来是因为PIL加载图片的方式。我尝试了一下,发现 PIL 可以很好地处理 alpha 和 RGB 值。

检查代码后,我注意到一件事我不喜欢:

panel = tk.Label(master, image=ph, text="2", bg="white", compound=tk.CENTER, fg="#EFEFEF", font=("Helvetica", 14))

bg="white" 部分是我遇到的问题,因为我确信 tcl/tk 的来源会干扰图像透明位的 RGB 值。现在,我无法访问 tcl/tk 源代码,因为我不知道如何访问它(抱歉,仍然是编程新手)。但我的猜测是,引用的代码行对图片的作用是这样的:它采用默认值或由用户设置bg 值,蚂蚁将其溅到我们的透明图像上,使整个透明度变得毫无用处。那我们该怎么办?好吧,我们必须为此过程准备图像 - 进行预乘。编辑后的代码发布在下面。下面我发布了我所拥有的示例:

图像看起来仍然有点像素化。我相信阅读更多有关预乘的信息并找到处理背景设置的 tcl/tk 源将允许为预乘选择更好的参数。或者,您可以尝试手动将图像与白色背景组合,并尝试不同的方法来进行预乘。

一些参考资料:

问题的原因在这里描述得很好(查看 cmets 以获得更多有用的信息):https://nedbatchelder.com/blog/200801/truly_transparent_text_with_pil.html

这里也有一个关于预乘的很好的解释: http://www.spherevfx.com/written-training/miscellaneous-written-training/understanding-premultiplied-images/

希望对您有所帮助:

import tkinter as tk
from PIL import Image, ImageTk

master = tk.Tk()
master.geometry("500x500")
master.attributes("-topmost", True)
master.configure(background='white')
master.attributes("-transparentcolor", "white")

im = Image.open('A.tif')
width, height = im.size
px = im.load()
for i in range(width):
    for j in range(height):
        if px[i, j][3] != 0 and px[i, j][3] != 255:
            R = int(round(px[i, j][1] * px[i, j][3]))
            G = int(round(px[i, j][1] * px[i, j][3]))
            B = int(round(px[i, j][1] * px[i, j][3]))
            a = px[i, j][3]

            px[i, j] = (R, G, B, a)
            print(px[i, j])


ph = ImageTk.PhotoImage(im)
panel = tk.Label(master, image=ph, text="2", bg="white", compound=tk.CENTER,
                 fg="#EFEFEF", font=("Helvetica", 14))
panel.pack()
panel.image = ph  # image reference

tk.mainloop()

旁注:wm_attributes() 与 attributes() 完全相同 - 我更喜欢使用后者来减少打字。

结果:

【讨论】:

  • 感谢您的回答。不幸的是,这不起作用。仍然给出颗粒状的边缘。请参阅问题编辑中的图片。
  • 也许你可以发布你的原始图像来玩玩?
  • 嗨 Aivaras,原始图像已添加。
  • 嘿,比尔,我已经解决了这个问题 2 个小时,终于找到了解决方案。我发现这是预乘的问题,只是方式不同。我会尽快修改我的答案。
  • 嗨 Aivaras,我已经添加了结果图像,它或多或少是位图类型的图像。所以不幸的是,这种方法并没有真正奏效。但无论如何,感谢您的想法和努力。
【解决方案2】:

问题是创建了一个新图像。结果图像中的“白色”颜色不再是真正的白色,例如(255,255,223) 而不是 (255,255,255)。因此,透明蒙版不会覆盖这些像素并保持可见。

如果您有固定颜色背景,最简单的解决方案是创建一个没有白色透明但已经具有相同背景颜色的图标。您也可以将其设置为透明颜色。 如果不是这种情况,那么您可以考虑使用中性背景色而不是白色并将其用作透明色。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-29
    • 2023-03-18
    • 2013-01-07
    • 1970-01-01
    • 1970-01-01
    • 2014-03-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多