Advertisement

python录屏工具免费版

阅读量:

import cv2
import numpy as np
from mss import mss
import tkinter as tk
from tkinter import ttk, messagebox
from threading import Thread
import time
import PIL.Image, PIL.ImageTk
import os
from PIL import Image, ImageDraw, ImageFont, ImageOps

默认配置

DEFAULT_REGION = (0, 0, 1920, 1080)
FPS = 20
VIDEO_PATH = "screen_recording.mp4"
WATERMARK_TEXT = "小熊录屏工具-免费版"

全局变量

recording = False
out = None
start_time = 0
selected_region = None
watermark_enabled = False

class ScreenRecorder:
def init(self, root):
self.root = root
self.root.title("小熊录屏工具")
self.root.geometry("400x300")
self.root.resizable(False, False)

self.style = ttk.Style()
self.style.configure("TButton", padding=6, relief="flat", background="#4CAF50")

self.watermark_var = tk.BooleanVar()

self.create_widgets()

def create_widgets(self):
main_frame = ttk.Frame(self.root, padding="20")
main_frame.pack(fill=tk.BOTH, expand=True)

区域选择

region_frame = ttk.LabelFrame(main_frame, text="录制区域", padding="10")
region_frame.pack(fill=tk.X, pady=5)

self.select_btn = ttk.Button(region_frame, text="选择区域", command=self.select_region)
self.select_btn.pack(side=tk.LEFT)

self.fullscreen_btn = ttk.Button(region_frame, text="全屏录制", command=self.set_fullscreen_region)
self.fullscreen_btn.pack(side=tk.LEFT, padx=5)

self.region_label = ttk.Label(region_frame, text=f"区域: {DEFAULT_REGION[0]}x{DEFAULT_REGION[1]}-{DEFAULT_REGION[2]}x{DEFAULT_REGION[3]}")
self.region_label.pack(side=tk.LEFT, padx=10)

水印设置

watermark_frame = ttk.LabelFrame(main_frame, text="水印设置", padding="10")
watermark_frame.pack(fill=tk.X, pady=5)

self.watermark_checkbox = ttk.Checkbutton(watermark_frame, text="启用水印", variable=self.watermark_var)
self.watermark_checkbox.pack()

控制按钮

button_frame = ttk.Frame(main_frame)
button_frame.pack(pady=10)

self.start_btn = ttk.Button(button_frame, text="开始录制", command=self.start_recording, width=15)
self.start_btn.pack(side=tk.LEFT, padx=5)

self.stop_btn = ttk.Button(button_frame, text="停止录制", command=self.stop_recording, width=15, state=tk.DISABLED)
self.stop_btn.pack(side=tk.LEFT, padx=5)

def set_fullscreen_region(self):
"""设置全屏录制区域"""
with mss() as sct:
monitor = sct.monitors[1]
global selected_region
selected_region = (monitor["left"], monitor["top"], monitor["width"], monitor["height"])
self.region_label.config(text=f"区域: 全屏 {monitor['width']}x{monitor['height']}")

def select_region(self):
"""直接在屏幕主界面选择区域"""
self.root.withdraw()

创建全屏选择窗口

preview = tk.Toplevel(self.root)
preview.overrideredirect(True) # 移除窗口边框
preview.attributes('-topmost', True)

with mss() as sct:
monitor = sct.monitors[1]

获取主屏幕尺寸

screen_width = monitor["width"]
screen_height = monitor["height"]

设置窗口尺寸为屏幕尺寸

preview.geometry(f"{screen_width}x{screen_height}+0+0")

canvas = tk.Canvas(preview, cursor="cross")
canvas.pack()

screenshot = sct.grab(monitor)
img = PIL.Image.fromarray(np.array(screenshot))
self.photo = PIL.ImageTk.PhotoImage(image=img)

canvas.config(width=self.photo.width(), height=self.photo.height())
canvas.create_image(0, 0, anchor=tk.NW, image=self.photo)

start_x = start_y = end_x = end_y = 0

def on_mouse_down(event):
nonlocal start_x, start_y
start_x = event.x
start_y = event.y
canvas.delete("selection")
canvas.create_rectangle(start_x, start_y, start_x, start_y, outline='red', tag="selection")

def on_mouse_drag(event):
canvas.delete("selection")
canvas.create_rectangle(start_x, start_y, event.x, event.y, outline='red', tag="selection")

def on_mouse_up(event):
nonlocal end_x, end_y
end_x = event.x
end_y = event.y
x1 = min(start_x, end_x)
y1 = min(start_y, end_y)
x2 = max(start_x, end_x)
y2 = max(start_y, end_y)

global selected_region
selected_region = (x1, y1, x2 - x1, y2 - y1)
self.region_label.config(text=f"区域: {x1}x{y1}-{x2 - x1}x{y2 - y1}")
preview.destroy()
self.root.deiconify()

canvas.bind("", on_mouse_down)
canvas.bind("", on_mouse_drag)
canvas.bind("", on_mouse_up)

preview.mainloop()

def init_writer(self):
"""初始化视频写入器"""
global out
width = selected_region[2] if selected_region else DEFAULT_REGION[2]
height = selected_region[3] if selected_region else DEFAULT_REGION[3]

fourcc = cv2.VideoWriter_fourcc(*"mp4v")
out = cv2.VideoWriter(VIDEO_PATH, fourcc, FPS, (width, height))

def apply_rotated_watermark(self, frame):
"""添加居中旋转水印(支持中文)"""
if not self.watermark_var.get():
return frame

水印参数

font_size = 86
font_color = (128, 128, 128) # 灰色
angle = 10 # 旋转角度
alpha = 0.5 # 透明度

创建PIL图像

pil_img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(pil_img)

加载中文字体(请根据实际路径修改)

try:
font_path = "simsun.ttc" # Windows系统自带字体
font = ImageFont.truetype(font_path, font_size)
except:

如果找不到中文字体,使用默认字体(可能显示乱码)

font = ImageFont.load_default()
print("警告:未找到中文字体文件,水印可能显示异常")

计算文本尺寸

text_width, text_height = draw.textsize(WATERMARK_TEXT, font=font)

创建水印图像

watermark = Image.new('RGBA', (text_width, text_height), (0, 0, 0, 0))
draw_wm = ImageDraw.Draw(watermark)
draw_wm.text((0, 0), WATERMARK_TEXT, font=font, fill=font_color + (int(255 * alpha),))

旋转水印

rotated_watermark = watermark.rotate(angle, expand=True)

计算水印位置(居中)

img_width, img_height = pil_img.size
wm_width, wm_height = rotated_watermark.size
position = (
(img_width - wm_width) // 2,
(img_height - wm_height) // 2
)

合成水印

pil_img.paste(rotated_watermark, position, rotated_watermark)

转换回OpenCV格式

frame = cv2.cvtColor(np.array(pil_img), cv2.COLOR_RGB2BGR)
return frame

def record(self):
"""录制线程"""
global recording, out
with mss() as sct:
while recording:
if selected_region:
monitor = {
"top": selected_region[1],
"left": selected_region[0],
"width": selected_region[2],
"height": selected_region[3]
}
else:
monitor = {"top": 0, "left": 0, "width": DEFAULT_REGION[2], "height": DEFAULT_REGION[3]}

img = sct.grab(monitor)
frame = np.array(img)
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)

添加旋转水印

frame = self.apply_rotated_watermark(frame)

out.write(frame)
time.sleep(1 / FPS)

def start_recording(self):
"""开始录制"""
global recording, start_time
if not recording:
recording = True
self.init_writer()
Thread(target=self.record, daemon=True).start()
start_time = time.time()
self.start_btn.config(text="暂停录制")
self.stop_btn.config(state=tk.NORMAL)
messagebox.showinfo("提示", "录制已开始!")

def stop_recording(self):
"""停止录制"""
global recording
if recording:
recording = False
out.release()
elapsed_time = time.strftime("%H小时%M分钟%S秒", time.gmtime(time.time() - start_time))
messagebox.showinfo("完成", f"录制完成!\n文件: {VIDEO_PATH}\n耗时: {elapsed_time}")
self.start_btn.config(text="开始录制")
self.stop_btn.config(state=tk.DISABLED)

if name == "main":
root = tk.Tk()
app = ScreenRecorder(root)
root.mainloop()

全部评论 (0)

还没有任何评论哟~