本文介紹用PIL和tkinter實作螢幕選取區域截圖功能。
一、實作思路
- 用tkinter建立全屏視窗,設定視窗半透明,用作截圖視窗
- 用tkinter綁定滑鼠按下、釋放、按下移動事件,擷取截取區域的起始坐标
- 用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系統存在縮放功能,是以要擷取原始和縮放後的分辨率,計算縮放比,截取圖形時對坐标進行縮放,如果沒有縮放就會導緻截取的區域不準
- 滑鼠左鍵按下時擷取開始坐标
- 滑鼠左鍵按下移動時,繪制矩形選擇區域
- 滑鼠左鍵釋放時,截取圖像