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

☆樱花仙子☆ 提交于 2020-04-16 01:56:26

问题


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

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)

回答1:


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:

Show the capture image after selecting region:




回答2:


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()


来源:https://stackoverflow.com/questions/60769486/how-to-give-dynamic-value-for-area-selection-in-imagegrab-library-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!