pixel-hunter/screenshot_selector.py
2026-07-29 21:12:25 +03:00

110 lines
3.4 KiB
Python

import tkinter as tk
from tkinter import filedialog
from PIL import Image, ImageTk
class ScreenshotSelector:
def __init__(self, parent, output_path, initial_path=None):
self.parent = parent
self.output_path = output_path
self.saved = False
self.start_x = None
self.start_y = None
self.rect = None
path = initial_path
if not path:
path = filedialog.askopenfilename(
parent=parent,
title='Choose a reference screenshot',
filetypes=[
('Images', '*.png *.jpg *.jpeg *.bmp *.webp'),
('All files', '*.*'),
],
)
if not path:
return
self.image = Image.open(path).convert('RGB')
max_w = max(300, parent.winfo_screenwidth() - 100)
max_h = max(300, parent.winfo_screenheight() - 160)
self.scale = min(1.0, max_w / self.image.width, max_h / self.image.height)
shown_size = (
max(1, round(self.image.width * self.scale)),
max(1, round(self.image.height * self.scale)),
)
self.shown = self.image.resize(shown_size, Image.Resampling.LANCZOS)
self.root = tk.Toplevel(parent)
self.root.title('Select the object or area to find')
self.root.attributes('-topmost', True)
self.root.protocol('WM_DELETE_WINDOW', self.root.destroy)
label = tk.Label(
self.root,
text='Drag a rectangle around the exact object/area to find',
padx=8,
pady=6,
)
label.pack(fill='x')
self.canvas = tk.Canvas(
self.root,
width=shown_size[0],
height=shown_size[1],
cursor='cross',
highlightthickness=0,
)
self.canvas.pack()
self.photo = ImageTk.PhotoImage(self.shown)
self.canvas.create_image(0, 0, image=self.photo, anchor='nw')
self.canvas.bind('<ButtonPress-1>', self.on_press)
self.canvas.bind('<B1-Motion>', self.on_drag)
self.canvas.bind('<ButtonRelease-1>', self.on_release)
self.root.grab_set()
self.parent.wait_window(self.root)
def on_press(self, event):
self.start_x, self.start_y = event.x, event.y
if self.rect is not None:
self.canvas.delete(self.rect)
self.rect = self.canvas.create_rectangle(
event.x,
event.y,
event.x,
event.y,
outline='#ff00ff',
width=3,
)
def on_drag(self, event):
if self.rect is not None:
self.canvas.coords(
self.rect,
self.start_x,
self.start_y,
event.x,
event.y,
)
def on_release(self, event):
x1, x2 = sorted((self.start_x, event.x))
y1, y2 = sorted((self.start_y, event.y))
if x2 - x1 < 10 or y2 - y1 < 10:
return
box = (
max(0, round(x1 / self.scale)),
max(0, round(y1 / self.scale)),
min(self.image.width, round(x2 / self.scale)),
min(self.image.height, round(y2 / self.scale)),
)
self.image.crop(box).save(self.output_path)
self.saved = True
self.root.destroy()
def select_from_screenshot(parent, output_path, initial_path=None):
return ScreenshotSelector(parent, output_path, initial_path).saved