I'm trying to create a screenshot area tool which can be triggered from python code.
It works at first call but, on second call I get bellow error:
TclError: image "pyimage2" doesn't exist
Only after I restart the kernel will work, but only once, then the same error appears..
I included all the code bellow. Has python-mss as a dependency (and tkinter on linux)
import os
from tkinter import Tk, Canvas, PhotoImage, YES, BOTH, NW, Toplevel
from mss import mss, tools
def full_screenshot(fn="img"):
# Primary monitor screenshot
filename = os.path.relpath(f'{fn}.png')
with mss() as sct:
sct.shot(mon=1, output=filename)
return filename
def area_screenshot(sx, sy, ex, ey, fn="img"):
try:
os.mkdir("snaps")
except:
pass
with mss() as sct:
# The screen part to capture
monitor = {"top": sy, "left": sx, "width": ex-sx, "height": ey-sy, "mon":1}
filename = os.path.relpath("./snaps/" + fn + "-{top}x{left}_{width}x{height}.png".format(**monitor))
# Grab the data
sct_img = sct.grab(monitor)
# Save to the picture file
tools.to_png(sct_img.rgb, sct_img.size, output=filename)
del sct
return filename
class _Snap:
def __init__(self, name="snap"):
self.name = name
self.snap = None
self.window = Tk()
#self.window = Toplevel(root)
self.window.title("Snip picture")
self.window.attributes('-fullscreen', True)
self.c = Canvas(self.window, cursor="cross")
self.c.pack(expand=YES, fill=BOTH)
fname = full_screenshot("temp")
bg = PhotoImage(file=fname)
self.c.create_image(0, 0, image=bg, anchor=NW)
self.window.bind("<Escape>", self.quit_fullscreen)
self.c.bind("<ButtonPress-1>", self.on_press)
self.c.bind("<B1-Motion>", self.on_drag)
self.c.bind("<ButtonRelease-1>", self.on_release)
self.window.mainloop()
#root.mainloop()
def quit_fullscreen(self, event):
self.window.attributes("-fullscreen", False)
def clear_canvas(self):
self.c.delete(self.rect)
self.c.delete(self.d1)
self.c.delete(self.d2)
self.window.update()
def on_press(self, event):
#print("Pressed", event)
self.sx = event.x
self.sy = event.y
self.rect = self.c.create_rectangle(self.sx, self.sy, self.sx, self.sy, width=2, fill="", dash=(3,5), outline="green3")
self.d1 = self.c.create_line(self.sx, self.sy, self.sx, self.sy, width=1.2, fill="green2")
self.d2 = self.c.create_line(self.sx, self.sy, self.sx, self.sy, width=1.2, fill="green2")
def on_drag(self, event):
#print("Draged", event)
self.cx = event.x
self.cy = event.y
self.c.coords(self.rect, self.sx, self.sy, self.cx, self.cy)
self.c.coords(self.d1, self.sx, self.sy, self.cx, self.cy)
self.c.coords(self.d2, self.cx, self.sy, self.sx, self.cy)
def on_release(self, event):
#print("Released", event)
self.ex = event.x
self.ey = event.y
self.clear_canvas()
self.snap = area_screenshot(self.sx, self.sy, self.ex, self.ey, self.name)
self.close_snip_window()
def close_snip_window(self):
os.remove("temp.png")
self.window.withdraw()
self.window.quit()
#Main function
def take_snap():
obj = _Snap()
cx = (obj.sx + obj.ex) / 2
cy = (obj.sy + obj.ey) / 2
data = {
"sxy": (obj.sx, obj.sy,),
"exy": (obj.ex, obj.ey,),
"cxy": (cx, cy,),
"snap": obj.snap
}
del obj
return data
#take_snap()
I tried with Toplevel() function but it didn't worked.
When you create an image, it stored with the main Tk window by default. Since you are creating another Tk window, you need to specify the image window.
Try this update: