79178428

Date: 2024-11-11 16:40:52
Score: 1
Natty:
Report link

Just a little bit math:

img = ImageGrab.grab()
# crop with correct scale
screen_width = self.master.winfo_screenwidth()
screen_height = self.master.winfo_screenheight()
x1 = x1 / screen_width * img.width
x2 = x2 / screen_width * img.width
y1 = y1 / screen_height * img.height
y2 = y2 / screen_height * img.height
img = img.crop(box=(x1, y1, x2, y2))

In addition, don't use bbox because it will reduce the quality. Use img.crop() instead.

Btw your code is not usable on mac. But I have a cross platform version of a snipping tool, DragScreenshot.py:

"""
Ver 1.0

StackOverflow answer: https://stackoverflow.com/a/79166810/18598080

Bruh. Finally made it.
it mainly supports Mac(tested) and Windows(not tested but supposed to work). In Linux (not tested), the dragging view will not be totally transparent.

Example:

import tkinter as tk
import TkDragScreenshot as dshot

root = tk.Tk()
root.withdraw()

def callback(img):
    img.save("a.png")
    quit()
def cancel_callback():
    print("User clicked / dragged 0 pixels.")
    quit()

dshot.drag_screen_shot(root, callback, cancel_callback)

root.mainloop()
"""

import platform
import tkinter as tk
from PIL import ImageGrab

using_debug_mode = None

class DragScreenshotPanel:  
    def __init__(self, root: tk.Tk, master: tk.Toplevel | tk.Tk, callback = None, cancel_callback = None):
        self.root = root
        self.master = master
        self.callback = callback
        self.cancel_callback = cancel_callback
        self.start_x = None
        self.start_y = None
        self.rect = None
        self.canvas = tk.Canvas(master, cursor="cross", background="black")
        self.canvas.pack(fill=tk.BOTH, expand=True)  
        self.canvas.config(bg=master["bg"])
        self.canvas.bind("<Button-1>", self.on_button_press)
        self.canvas.bind("<B1-Motion>", self.on_mouse_drag)
        self.canvas.bind("<ButtonRelease-1>", self.on_button_release)

    def on_button_press(self, event):
        self.start_x = event.x
        self.start_y = event.y
        self.rect = self.canvas.create_rectangle(self.start_x, self.start_y, self.start_x, self.start_y, outline='white', width=2)  

    def on_mouse_drag(self, event):  
        self.canvas.coords(self.rect, self.start_x, self.start_y, event.x, event.y)

    def on_button_release(self, event):
        x1 = min(self.start_x, event.x)
        y1 = min(self.start_y, event.y)
        x2 = max(self.start_x, event.x)
        y2 = max(self.start_y, event.y)
        self.canvas.delete(self.rect)
        dy = abs(y2-y1)
        dx = abs(x2-x1)
        if dy*dx != 0:
            self.master.withdraw()
            img = ImageGrab.grab()
            screen_width = self.master.winfo_screenwidth()
            screen_height = self.master.winfo_screenheight()
            x1 = x1 / screen_width * img.width
            x2 = x2 / screen_width * img.width
            y1 = y1 / screen_height * img.height
            y2 = y2 / screen_height * img.height
            img = img.crop(box=(x1, y1, x2, y2))
            if using_debug_mode: print("Screenshot taken!")
            self.root.after(1, self.callback(img))
            self.master.deiconify()
            self.master.focus_force()
        else:
            if using_debug_mode: print("Screenshot canceled!")
            self.root.after(1, self.cancel_callback())
        
        self.master.destroy()
        


def set_bg_transparent(toplevel:tk.Toplevel, invisible_color_Windows_OS_Only= '#100101'):
    if platform.system() == "Windows":
        toplevel.attributes("-transparentcolor", invisible_color_Windows_OS_Only)
        toplevel.config(bg=invisible_color_Windows_OS_Only)
    elif platform.system() == "Darwin":
        toplevel.attributes("-transparent", True)
        toplevel.config(bg="systemTransparent")
    else:
        if using_debug_mode: print(f"Total transparency is not supported on this OS. platform.system() -> '{platform.system()}'")
        window_alpha_channel = 0.3
        toplevel.attributes('-alpha', window_alpha_channel)
        toplevel.lift()
        toplevel.attributes("-topmost", True)
        toplevel.attributes("-transparent", True)


def drag_screen_shot(root:tk.Tk, callback = None, cancel_callback = None, debug_logging = False):
    global using_debug_mode

    using_debug_mode = debug_logging

    top = tk.Toplevel(root)
    top.geometry(f"{root.winfo_screenwidth()}x{root.winfo_screenheight()}+0+0")
    top.overrideredirect(True)
    top.lift()
    top.attributes("-topmost", True)

    set_bg_transparent(top)
    DragScreenshotPanel(root, top, callback, cancel_callback)

just make a root with tk and then call drag_screen_shot(root, on_capture, on_cancel)

Reasons:
  • Blacklisted phrase (1): StackOverflow
  • Blacklisted phrase (1): stackoverflow
  • Long answer (-1):
  • Has code block (-0.5):
  • Low reputation (0.5):
Posted by: Jacky