Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to give dynamic value for area selection in imagegrab library in python

Using this script i am trying to take a screenshot of my desktop of a particular area.(using Tkinter gui)

But with this code i can only take screenshot of the fix area (frame) of desktop. So what i want to do is try to set the value of (bbox of imagegrab) dynamic.

And by dynamic i mean it should only capture the screen area which is selected(highlighted) by my mouse cursor any where on screen and can be of any size.

import tkinter as tk
from tkinter import *
from PIL import Image, ImageGrab 
root = tk.Tk()
def area_sel():    
     # using the grab method 
     img = ImageGrab.grab(bbox = (400,500,400,500)) #i want these values to be dynamic
     img.show() 

sel_btn = tk.Button(root, text='select area', width=20, command=area_sel)
sel_btn.pack()

root.mainloop()

example image area

here is what i am trying to do is to take coordinates from your code and then recording that particular area of screen.

def recording_screen():

    global recording
    recording = True

    while recording:
        sel=area_sel()    
        img = ImageGrab.grab(bbox=(Click_x, Click_y, Release_x, Release_y))
        frame = np.array(img)
        out.write(frame)
like image 661
amit9867 Avatar asked Oct 20 '25 08:10

amit9867


2 Answers

You can use Pillow to do what you want:

import tkinter as tk
from PIL import Image, ImageTk, ImageGrab, ImageEnhance

root = tk.Tk()
root.resizable(0, 0)

def show_image(image):
    win = tk.Toplevel()
    win.image = ImageTk.PhotoImage(image)
    tk.Label(win, image=win.image).pack()
    win.grab_set()
    win.wait_window(win)

def area_sel():
    x1 = y1 = x2 = y2 = 0
    roi_image = None

    def on_mouse_down(event):
        nonlocal x1, y1
        x1, y1 = event.x, event.y
        canvas.create_rectangle(x1, y1, x1, y1, outline='red', tag='roi')

    def on_mouse_move(event):
        nonlocal roi_image, x2, y2
        x2, y2 = event.x, event.y
        canvas.delete('roi-image') # remove old overlay image
        roi_image = image.crop((x1, y1, x2, y2)) # get the image of selected region
        canvas.image = ImageTk.PhotoImage(roi_image)
        canvas.create_image(x1, y1, image=canvas.image, tag=('roi-image'), anchor='nw')
        canvas.coords('roi', x1, y1, x2, y2)
        # make sure the select rectangle is on top of the overlay image
        canvas.lift('roi') 

    root.withdraw()  # hide the root window
    image = ImageGrab.grab()  # grab the fullscreen as select region background
    bgimage = ImageEnhance.Brightness(image).enhance(0.3)  # darken the capture image
    # create a fullscreen window to perform the select region action
    win = tk.Toplevel()
    win.attributes('-fullscreen', 1)
    win.attributes('-topmost', 1)
    canvas = tk.Canvas(win, highlightthickness=0)
    canvas.pack(fill='both', expand=1)
    tkimage = ImageTk.PhotoImage(bgimage)
    canvas.create_image(0, 0, image=tkimage, anchor='nw', tag='images')
    # bind the mouse events for selecting region
    win.bind('<ButtonPress-1>', on_mouse_down)
    win.bind('<B1-Motion>', on_mouse_move)
    win.bind('<ButtonRelease-1>', lambda e: win.destroy())
    # use Esc key to abort the capture
    win.bind('<Escape>', lambda e: win.destroy())
    # make the capture window modal
    win.focus_force()
    win.grab_set()
    win.wait_window(win)
    root.deiconify()  # restore root window
    # show the capture image
    if roi_image:
        show_image(roi_image)

tk.Button(root, text='select area', width=30, command=area_sel).pack()

root.mainloop()

During selecting region:

enter image description here

Show the capture image after selecting region:

enter image description here

like image 162
acw1668 Avatar answered Oct 22 '25 22:10

acw1668


Use pynput is a way to do this(Maybe only use tkinter can do this,but I don't know),You only need to know the position of mouse button pressed and mouse button released:

Read more about pynput module

import tkinter as tk
# from tkinter import *
from PIL import Image, ImageGrab,ImageTk
from pynput import mouse
from pynput.keyboard import Key, Listener


def getPostion():
    def on_click(x, y, button, pressed):
        global Click_x, Click_y, Release_x, Release_y, STOP
        if pressed:
            Click_x = x
            Click_y = y
        else:
            Keyboardlistener.stop()
            Release_x = x
            Release_y = y
            STOP = False
            return False

    def on_release(key):
        global STOP
        if key == Key.esc:
            Mouselistener.stop()
            STOP = True
            return False

    with mouse.Listener(on_click=on_click) as Mouselistener, Listener(on_release=on_release) as Keyboardlistener:
        Mouselistener.join()
        Keyboardlistener.join()


root = tk.Tk()
def area_sel():
    global Click_x, Click_y, Release_x, Release_y, STOP
    Click_x, Click_y, Release_x, Release_y= 0,0,0,0
    # using the grab method
    top = tk.Toplevel() # create a toplevel
    top.wm_attributes('-alpha',0.3)
    top.state('zoomed') # make window fullscreen
    top.overrideredirect(1)

    # background = ImageTk.PhotoImage(image=ImageGrab.grab()) # get a screenshot
    fullCanvas = tk.Canvas(top) # make a fullscreen canvas
    # fullCanvas.create_image(xx,xx)  # create a screenshot image in this canvas.


    fullCanvas.pack()
    top.update()
    getPostion()
    if Click_x and Click_y and Release_x and Release_y:
        if STOP:
            return False
        top.withdraw()
        img = ImageGrab.grab(bbox = (Click_x, Click_y, Release_x, Release_y))
        img.show()


STOP = False
sel_btn = tk.Button(root, text='select area', width=20, command=area_sel)
sel_btn.pack()

root.mainloop()

edit now it is a complete tool can take a scroonshot,it is needn't to use pynput full code :

import tkinter as tk
# from tkinter import *
from PIL import Image, ImageGrab, ImageTk
import ctypes, sys

if sys.getwindowsversion().major == 10:
    ctypes.windll.shcore.SetProcessDpiAwareness(2) # Set DPI awareness


root = tk.Tk()
def area_sel():
    def getPress(event): # get press position
        global press_x,press_y
        press_x,press_y = event.x,event.y

    def mouseMove(event): # movement
        global press_x, press_y, rectangleId
        fullCanvas.delete(rectangleId)
        rectangleId = fullCanvas.create_rectangle(press_x,press_y,event.x,event.y,width=5)

    def getRelease(event): # get release position
        global press_x, press_y, rectangleId
        top.withdraw()
        img = ImageGrab.grab((press_x, press_y,event.x,event.y))
        img.show()

    top = tk.Toplevel()
    top.state('zoomed')
    top.overrideredirect(1)
    fullCanvas = tk.Canvas(top)

    background = ImageTk.PhotoImage(ImageGrab.grab().convert("L"))
    fullCanvas.create_image(0,0,anchor="nw",image=background)

    # bind event for canvas
    fullCanvas.bind('<Button-1>',getPress)
    fullCanvas.bind('<B1-Motion>',mouseMove)
    fullCanvas.bind('<ButtonRelease-1>',getRelease)

    fullCanvas.pack(expand="YES",fill="both")
    top.mainloop()

rectangleId = None
sel_btn = tk.Button(root, text='select area', width=20, command=area_sel)
sel_btn.pack()

root.mainloop()
like image 20
jizhihaoSAMA Avatar answered Oct 22 '25 22:10

jizhihaoSAMA



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!