天天看點

python3用PIL+tkinter實作螢幕選取區域截圖功能

本文介紹用PIL和tkinter實作螢幕選取區域截圖功能。

一、實作思路

  1. 用tkinter建立全屏視窗,設定視窗半透明,用作截圖視窗
  2. 用tkinter綁定滑鼠按下、釋放、按下移動事件,擷取截取區域的起始坐标
  3. 用PIL實作通過起始坐标截圖

二、代碼實作

from time import sleep
from PIL import Image, ImageGrab
import tkinter
import ctypes

class CTkPrScrn:
    def __init__(self):
        self.__start_x, self.__start_y = 0, 0
        self.__scale = 1

        self.__win = tkinter.Tk()
        self.__win.attributes("-alpha", 0.5)  # 設定視窗半透明
        self.__win.attributes("-fullscreen", True)  # 設定全屏
        self.__win.attributes("-topmost", True)  # 設定視窗在最上層

        self.__width, self.__height = self.__win.winfo_screenwidth(), self.__win.winfo_screenheight()

        # 建立畫布
        self.__canvas = tkinter.Canvas(self.__win, width=self.__width, height=self.__height, bg="gray")

        self.__win.bind('<Button-1>', self.xFunc1)  # 綁定滑鼠左鍵點選事件
        self.__win.bind('<ButtonRelease-1>', self.xFunc1)  # 綁定滑鼠左鍵點選釋放事件
        self.__win.bind('<B1-Motion>', self.xFunc2)  # 綁定滑鼠左鍵點選移動事件
        self.__win.bind('<Escape>', lambda e: self.__win.destroy())  # 綁定Esc按鍵退出事件

        user32 = ctypes.windll.user32
        gdi32 = ctypes.windll.gdi32
        dc = user32.GetDC(None)
        widthScale = gdi32.GetDeviceCaps(dc, 8)  # 分辨率縮放後的寬度
        heightScale = gdi32.GetDeviceCaps(dc, 10)  # 分辨率縮放後的高度
        width = gdi32.GetDeviceCaps(dc, 118)  # 原始分辨率的寬度
        height = gdi32.GetDeviceCaps(dc, 117)  # 原始分辨率的高度
        self.__scale = width / widthScale
        print(self.__width, self.__height, widthScale, heightScale, width, height, self.__scale)

        self.__win.mainloop()  # 視窗持久化

    def xFunc1(self, event):
        # print(f"滑鼠左鍵點選了一次坐标是:x={g_scale * event.x}, y={g_scale * event.y}")
        if event.state == 8:  # 滑鼠左鍵按下
            self.__start_x, self.__start_y = event.x, event.y
        elif event.state == 264:  # 滑鼠左鍵釋放
            if event.x == self.__start_x or event.y == self.__start_y:
                return
            im = ImageGrab.grab((self.__scale * self.__start_x, self.__scale * self.__start_y,
                                 self.__scale * event.x, self.__scale * event.y))
            imgName = 'tmp.png'
            im.save(imgName)

            print('儲存成功')
            self.__win.update()
            sleep(0.5)
            self.__win.destroy()

    def xFunc2(self, event):
        # print(f"滑鼠左鍵點選了一次坐标是:x={self.__scale * event.x}, y={self.__scale * event.y}")
        if event.x == self.__start_x or event.y == self.__start_y:
            return
        self.__canvas.delete("prscrn")
        self.__canvas.create_rectangle(self.__start_x, self.__start_y, event.x, event.y,
                                       fill='white', outline='red', tag="prscrn")
        # 包裝畫布
        self.__canvas.pack()

if __name__ == '__main__':
    prScrn = CTkPrScrn()
           

說明:

  • 因為windows系統存在縮放功能,是以要擷取原始和縮放後的分辨率,計算縮放比,截取圖形時對坐标進行縮放,如果沒有縮放就會導緻截取的區域不準
  • 滑鼠左鍵按下時擷取開始坐标
  • 滑鼠左鍵按下移動時,繪制矩形選擇區域
  • 滑鼠左鍵釋放時,截取圖像

繼續閱讀