使用tkinter的Cairo?

4 投票
1 回答
2257 浏览
提问于 2025-04-18 18:25

可以在Cairo表面上绘图,然后把它显示成tkinter.PhotoImage吗?有没有人能给个例子,或者至少描述一下怎么做到这一点?

1 个回答

3

有很多方法可以实现你想要的效果,而tkinter.PhotoImage绝对不是最好的选择,除非你真的必须使用它。最简单的方法是使用Pillow库中的ImageTK模块

from tkinter import Tk, Label
from PIL import Image, ImageTk
from cairo import ImageSurface, Context, FORMAT_ARGB32


class ExampleGui(Tk):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        w, h = 800, 600

        self.geometry("{}x{}".format(w, h))

        self.surface = ImageSurface(FORMAT_ARGB32, w, h)
        self.context = Context(self.surface)

        # Draw something
        self.context.scale(w, h)
        self.context.rectangle(0, 0, 1, 1)
        self.context.set_source_rgba(1, 0, 0, 0.8)
        self.context.fill()

        self._image_ref = ImageTk.PhotoImage(Image.frombuffer("RGBA", (w, h), self.surface.get_data(), "raw", "BGRA", 0, 1))

        self.label = Label(self, image=self._image_ref)
        self.label.pack(expand=True, fill="both")

        self.mainloop()


if __name__ == "__main__":
    ExampleGui()

另外,你也可以通过将cairo的表面转换为base64编码的GIF图像来实现(可以借助Pillow,或者手动转换,不过手动会比较耗时间),然后把结果作为“data”参数传给tkinter.PhotoImage构造函数(未经测试!):

    from io import BytesIO 
    from PIL import Image
    from cairo import ImageSurface, Context, FORMAT_ARGB32


    w, h = 800, 600

    surface = ImageSurface(FORMAT_ARGB32, w, h)
    context = Context(surface)

    output = io.BytesIO()
    image = Image.frombuffer("RGBA", (w, h), self.surface.get_data(), "raw", "BGRA", 0, 1)
    image.save(output, format="gif")
    b64 = base64.b64encode(output.read())

注意:在大端机器上,源数据应该使用“ARGB”模式,尽我所知。

撰写回答