【问题标题】:Canvas ouput different from PIL saved image画布输出不同于 PIL 保存图像
【发布时间】:2021-03-24 09:18:51
【问题描述】:

您好,我正在开发一个小绘图程序。它基本上在按下鼠标时在 tkinter Canvas 上绘制圆圈,同时在 PIL 图像上绘制圆圈(具有相同的圆圈属性)。

我的问题是圆半径太小,当我移动得太快而无法绘制圆链时,我没有相同的 tkinter 输出和 PIL 图像输出。

我正在使用 python 3.8.5 和 PIL 7.0.0

#! /usr/bin/env python3

import tkinter as tk
from tkinter import *
from PIL import Image,ImageDraw,ImageTk

class App(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        #Tkinter Classical Canvas:
        self.canv= Canvas(self, bg="white", height=500,
                              width=500)
        self.canv.pack()
        #identic sized  PIL image:
        self.image1 = Image.new("RGB", (500, 500), "white")
        self.draw = ImageDraw.Draw(self.image1)
        self.buttons()

    def buttons(self):
        #size of the diameter parameter "button":
        self.choose_diam_button =Scale(self, from_=1, to=100, orient=HORIZONTAL)
        self.choose_diam_button.pack()

        self.bouton_save = Button(self, text="save",font = "Ubuntu",
                                        command=self.save)
        self.bouton_save.pack()

        self.setup()

    def save(self):
        self.chiffre_status=0
        #the file is saved in an "IMG_DATA" gif file in directory
        self.filename = "IMG_DATA"
        self.image1.save(self.filename , format='GIF')



    def reset(self, event):
        self.old_x, self.old_y = None, None

    def setup(self):
        self.old_x = None
        self.old_y = None
        #boutton de taille du pinceau
        self.diameter = self.choose_diam_button.get()
        self.color = 'black'

        self.canv.bind('<B1-Motion>', self.paint)
        self.canv.bind('<ButtonRelease-1>', self.reset)

    def paint(self,event):
        self.diameter = self.choose_diam_button.get()
        if self.old_x and self.old_y:
          self.x=event.x+self.diameter
          self.y=event.y+self.diameter
          #The next line draws on the visible tkinter Canvas
          self.canv.create_oval(self.old_x, self.old_y,self.x ,self.y ,
                                outline=self.color, fill=self.color)
        #The next line draws on the PIL invisible image1
          self.draw.ellipse([self.old_x, self.old_y, self.x, self.y],outline=self.color, fill=self.color)

        self.old_x = event.x
        self.old_y = event.y

appli = App()
appli.title("stack question")
appli.mainloop()

Tkinter 可见输出:

保存的“并行”PIL 图像:

【问题讨论】:

标签: tkinter python-imaging-library


【解决方案1】:

如果有人在 Linux 上工作,请找到我自己的问题的 2 个解决方案:

改编自这篇文章:

How can I convert canvas content to an image?

对于任何愿意通过首先在磁盘上保存 eps 文件来以任何格式保存 Canvas 的人: 只需将上面的保存功能更改为以下功能: 并行 PIL 绘图现在没用了,您可以将其删除。 它将首先保存一个 postscript 文件,然后以正确的格式重新保存它。 注意后记大小参数。 (适应你的)

def save(self):
    # save postscipt image 
    #!!!!!(NOTICE the pagewidth and pageheight arguments)!!!!!
    self.canv.postscript(file = "IMG_DATA" + '.eps',pagewidth=500, pageheight=500)
    # use PIL to convert to GIF
    self.img = Image.open("IMG_DATA" + '.eps')
    self.img.save("IMG_DATA" + '.gif', 'gif')

编辑:

最佳解决方案

从上面的链接中获取的另一个解决方案(按照下面的答案之一)是直接使用 ImageGrab.grab() 保存,给出图像的坐标,而不在磁盘上保存任何文件。在 linux 上没有 ImageGrab,所以你只需要安装 pyscreenshot:

import pyscreenshot as ImageGrab


    def save(self):
        #replace self.canv with your widget name
        x=self.winfo_rootx()+self.canv.winfo_x()
        y=self.winfo_rooty()+self.canv.winfo_y()
        x1=x+self.canv.winfo_width()
        y1=y+self.canv.winfo_height()
        ImageGrab.grab().crop((x,y,x1,y1)).save("IMG_DATA.gif")

编辑(2):

发现“最佳解决方案”存在问题: 当您的“绘画”窗口不是全屏并且您要复制的小部件稍微移出屏幕时,您可能会遇到这个问题: 不在屏幕上的部分无法复制,替换为黑色矩形。

【讨论】:

  • 您可以使用ImageGrab.grab(...) 将画布的快照拍摄到图像并保存图像。
  • 您不需要将其保存到磁盘上的文件中。您可以保存到 "in-memory" BytesIO 并使用 PIL 读取它以节省等待硬盘旋转并在文件系统中创建不必要的文件。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-04-11
  • 2013-02-08
  • 1970-01-01
  • 2013-11-08
  • 2015-07-15
  • 1970-01-01
  • 2017-08-16
相关资源
最近更新 更多