@ -1,9 +0,0 @@
|
||||
ffmpeg-python==0.2.0
|
||||
numba==0.54.1
|
||||
numpy==1.20.3
|
||||
opencv-python==4.5.4.60
|
||||
Pillow==8.4.0
|
||||
PyAudio
|
||||
pynput==1.7.5
|
||||
PyQt5==5.15.4
|
||||
py7zr==0.18.4
|
Before Width: | Height: | Size: 176 KiB |
Before Width: | Height: | Size: 1.8 KiB |
@ -1,9 +0,0 @@
|
||||
ffmpeg-python==0.2.0
|
||||
numba==0.54.1
|
||||
numpy==1.20.3
|
||||
opencv-python==4.5.4.60
|
||||
Pillow==8.4.0
|
||||
PyAudio
|
||||
pynput==1.7.5
|
||||
PyQt5==5.15.4
|
||||
py7zr==0.18.4
|
Before Width: | Height: | Size: 176 KiB |
@ -0,0 +1,171 @@
|
||||
# _*_ coding:utf-8 _*_
|
||||
import shutil
|
||||
from PIL import ImageGrab
|
||||
from PyQt5.QtCore import QCoreApplication, Qt, qAbs, QRect, QPoint
|
||||
from PyQt5.QtGui import QPen, QPainter, QIcon, QFont, QColor, QPixmap
|
||||
from PyQt5.QtWidgets import QPushButton, QHBoxLayout, QLabel, QVBoxLayout, QCheckBox, QMessageBox, QFileDialog, QDialog, \
|
||||
QApplication, QWidget, QDesktopWidget
|
||||
|
||||
from base import Base
|
||||
from config import ABSOLUTE_PATH
|
||||
from screen_record_thread import ScreenRecordThread, SaveMp4Thread
|
||||
|
||||
|
||||
class ScreenBar(Base):
|
||||
def __init__(self):
|
||||
super(ScreenBar, self).__init__()
|
||||
self.box = QVBoxLayout()
|
||||
self.btn_box = QHBoxLayout()
|
||||
self.tip_label = QLabel(' 屏幕录制 ')
|
||||
self.is_record_full = QCheckBox()
|
||||
self.open_btn = QPushButton()
|
||||
self.start_btn = QPushButton()
|
||||
self.end_btn = QPushButton()
|
||||
self.close_btn = QPushButton()
|
||||
self.recording_thread = ScreenRecordThread()
|
||||
self.offset_x = 0
|
||||
self.offset_y = 0
|
||||
self.end_x = 0
|
||||
self.end_y = 0
|
||||
self.bind()
|
||||
self.set_style()
|
||||
|
||||
def set_style(self):
|
||||
self.start_btn.setEnabled(False)
|
||||
self.end_btn.setEnabled(False)
|
||||
self.start_btn.setIcon(QIcon('screenshot_png/start.png'))
|
||||
self.end_btn.setIcon(QIcon('screenshot_png/stop.png'))
|
||||
self.close_btn.setIcon(QIcon('screenshot_png/close.png'))
|
||||
self.is_record_full.setIcon(QIcon('screenshot_png/full.png'))
|
||||
self.open_btn.setIcon(QIcon('screenshot_png/rect.png'))
|
||||
self.btn_box.addWidget(self.is_record_full, 0)
|
||||
self.btn_box.addWidget(self.open_btn, 0)
|
||||
self.btn_box.addWidget(self.start_btn, 0)
|
||||
self.btn_box.addWidget(self.end_btn, 0)
|
||||
self.btn_box.addWidget(self.close_btn, 0)
|
||||
self.box.addWidget(self.tip_label)
|
||||
self.box.addLayout(self.btn_box)
|
||||
self.box.setContentsMargins(0, 0, 0, 0)
|
||||
self.setWindowOpacity(0.7)
|
||||
self.frameGeometry()
|
||||
self.move(QApplication.desktop().frameGeometry().width() - 300,
|
||||
QApplication.desktop().frameGeometry().height() - 150)
|
||||
self.setLayout(self.box)
|
||||
|
||||
def thread_trigger_signal(self, list, fps, gif_list):
|
||||
def show_success_message(str):
|
||||
QMessageBox.information(self, "提示", str, QMessageBox.Yes)
|
||||
self.end_btn.setEnabled(False)
|
||||
self.open_btn.setEnabled(True)
|
||||
self.is_record_full.setEnabled(True)
|
||||
|
||||
path, tmp = QFileDialog.getSaveFileName(self,
|
||||
"文件保存",
|
||||
'%s/*.mp4' % ABSOLUTE_PATH,
|
||||
"All Files (*);")
|
||||
if not '' == path:
|
||||
if not path.endswith(".mp4"):
|
||||
path = path + ".mp4"
|
||||
self.save_mp4_thread = SaveMp4Thread(list, fps, path, gif_list)
|
||||
self.save_mp4_thread.trigger.connect(lambda: show_success_message("保存成功"))
|
||||
self.save_mp4_thread.start()
|
||||
else:
|
||||
show_success_message("取消保存")
|
||||
shutil.rmtree('temp')
|
||||
|
||||
def bind(self):
|
||||
def open_signal():
|
||||
SizeScreen = MousePaint()
|
||||
SizeScreen.exec_()
|
||||
self.offset_x, self.offset_y = SizeScreen.lastpoint
|
||||
self.end_x, self.end_y = SizeScreen.endpoint
|
||||
self.start_btn.setEnabled(True)
|
||||
self.is_record_full.setEnabled(False)
|
||||
|
||||
def start_signal():
|
||||
self.open_btn.setEnabled(False)
|
||||
self.start_btn.setEnabled(False)
|
||||
self.end_btn.setEnabled(True)
|
||||
self.recording_thread.recording = True
|
||||
if self.is_record_full.isChecked():
|
||||
self.recording_thread.area = None
|
||||
self.recording_thread.start()
|
||||
else:
|
||||
self.recording_thread.area = (self.offset_x, self.offset_y, self.end_x, self.end_y)
|
||||
self.recording_thread.start()
|
||||
|
||||
def end_signal():
|
||||
self.recording_thread.recording = False
|
||||
|
||||
def record_full_signal():
|
||||
if self.is_record_full.isChecked():
|
||||
self.open_btn.setEnabled(False)
|
||||
self.start_btn.setEnabled(True)
|
||||
else:
|
||||
self.open_btn.setEnabled(True)
|
||||
self.start_btn.setEnabled(False)
|
||||
|
||||
self.open_btn.clicked.connect(open_signal)
|
||||
self.start_btn.clicked.connect(start_signal)
|
||||
self.end_btn.clicked.connect(end_signal)
|
||||
self.close_btn.clicked.connect(lambda: self.close())
|
||||
self.is_record_full.stateChanged.connect(record_full_signal)
|
||||
self.recording_thread.trigger.connect(self.thread_trigger_signal)
|
||||
|
||||
class MousePaint(QDialog):
|
||||
"""移动鼠标获取屏幕捕获范围"""
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.setMouseTracking(True)
|
||||
# 设置窗口布满整个屏幕
|
||||
self.showFullScreen()
|
||||
# 设置窗体无边框
|
||||
self.setWindowFlags(Qt.FramelessWindowHint) # 窗口置顶,无边框
|
||||
# 设置背景透明
|
||||
self.setWindowOpacity(0.5)
|
||||
self.initUI()
|
||||
self.setFocus()
|
||||
|
||||
def initUI(self):
|
||||
self.setGeometry(*(QDesktopWidget().screenGeometry()).getRect())
|
||||
self.pix = QPixmap()
|
||||
self.lastpoint = QPoint()
|
||||
self.endpoint = QPoint()
|
||||
self.pos = None
|
||||
self.bline = 0
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
# 监听鼠标按压事件
|
||||
if event.button() == Qt.LeftButton:
|
||||
self.lastpoint = event.x(), event.y()
|
||||
self.bline = 1
|
||||
elif event.button() == Qt.RightButton:
|
||||
self.close()
|
||||
event.accept()
|
||||
|
||||
def mouseReleaseEvent(self, event):
|
||||
# 监听鼠标释放事件
|
||||
self.endpoint = event.x(), event.y()
|
||||
self.bline = 0
|
||||
event.accept()
|
||||
self.close()
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
# 监听鼠标移动事件
|
||||
if self.bline == 1:
|
||||
self.pos = event.x(), event.y()
|
||||
event.accept()
|
||||
self.update()
|
||||
|
||||
def paintEvent(self, event):
|
||||
# 绘画事件
|
||||
if self.bline == 1:
|
||||
pp = QPainter(self)
|
||||
pen = QPen() # 定义笔格式对象
|
||||
pen.setWidth(5) # 设置笔的宽度
|
||||
pen.setColor(QColor(255, 0, 0))
|
||||
pp.setPen(pen)
|
||||
lpx, lpy = self.lastpoint
|
||||
pp.drawRect(lpx, lpy, self.pos[0] - lpx, self.pos[1] - lpy)
|
||||
event.accept()
|
@ -0,0 +1,23 @@
|
||||
# _*_ coding:utf-8 _*_
|
||||
from PyQt5.QtCore import Qt
|
||||
from PyQt5.QtWidgets import QWidget, QApplication
|
||||
|
||||
|
||||
class Base(QWidget):
|
||||
def __init__(self):
|
||||
super(Base, self).__init__()
|
||||
self.mMoveing = True
|
||||
self.mMovePosition = self.pos()
|
||||
self.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint)
|
||||
|
||||
def mousePressEvent(self, QMouseEvent):
|
||||
self.mMoveing = True
|
||||
self.mMovePosition = QMouseEvent.globalPos() - self.pos()
|
||||
return super().mousePressEvent(QMouseEvent)
|
||||
|
||||
def mouseMoveEvent(self, QMouseEvent):
|
||||
if self.mMoveing and (QMouseEvent.buttons() and Qt.LeftButton) and (
|
||||
QMouseEvent.globalPos() - self.mMovePosition).manhattanLength() > QApplication.startDragDistance():
|
||||
self.move(QMouseEvent.globalPos() - self.mMovePosition)
|
||||
self.mMovePosition = QMouseEvent.globalPos() - self.pos()
|
||||
return super().mouseMoveEvent(QMouseEvent)
|
@ -0,0 +1,6 @@
|
||||
# _*_ coding:utf-8 _*_
|
||||
import os
|
||||
|
||||
ABSOLUTE_PATH = os.path.dirname(os.path.realpath(__file__)).replace('\\', '/')
|
||||
|
||||
|
@ -0,0 +1,71 @@
|
||||
# _*_ coding:utf-8 _*_
|
||||
import time
|
||||
|
||||
import os
|
||||
|
||||
import shutil
|
||||
|
||||
import win32gui
|
||||
from PIL import ImageGrab, Image
|
||||
from PyQt5.QtCore import QThread, pyqtSignal
|
||||
from moviepy.video.io.ImageSequenceClip import ImageSequenceClip
|
||||
|
||||
|
||||
class ScreenRecordThread(QThread):
|
||||
trigger = pyqtSignal(list, int, list)
|
||||
|
||||
def __init__(self):
|
||||
super(ScreenRecordThread, self).__init__()
|
||||
self.recording = True
|
||||
self.area = None
|
||||
self.save_path = ''
|
||||
self.is_pause_for_save = True
|
||||
self.recordTime = 0
|
||||
self.image_list = [] # mp4 list
|
||||
self.image_gif_list = [] # gif list
|
||||
|
||||
def run(self):
|
||||
if not os.path.exists('temp'):
|
||||
os.mkdir('temp')
|
||||
else:
|
||||
shutil.rmtree('temp')
|
||||
os.mkdir('temp')
|
||||
self.is_pause_for_save = True
|
||||
self.recording = True
|
||||
self.recordTime = 0
|
||||
self.image_list = []
|
||||
|
||||
t = time.time()
|
||||
imCursor = Image.open('screenshot_png/cursor.png')
|
||||
self.image_gif_list = []
|
||||
while self.recording:
|
||||
curX, curY = win32gui.GetCursorPos()
|
||||
if self.area is None:
|
||||
image = ImageGrab.grab()
|
||||
image.paste(imCursor, box=(curX, curY), mask=imCursor)
|
||||
else:
|
||||
image = ImageGrab.grab(self.area)
|
||||
image.paste(imCursor, box=(curX - self.area[0], curY - self.area[1]), mask=imCursor)
|
||||
imageName = os.path.join('temp', '%s.jpg' % int(time.time() * 1e3))
|
||||
image.save(imageName)
|
||||
self.image_list.append(imageName)
|
||||
self.recordTime = time.time() - t
|
||||
fps = len(self.image_list) / self.recordTime
|
||||
self.trigger.emit(self.image_list, fps, self.image_gif_list)
|
||||
|
||||
|
||||
class SaveMp4Thread(QThread):
|
||||
trigger = pyqtSignal()
|
||||
|
||||
def __init__(self, list, fps, path, gif_list):
|
||||
super(SaveMp4Thread, self).__init__()
|
||||
self.fps = fps
|
||||
self.path = path
|
||||
self.list = list
|
||||
self.gif_list = gif_list
|
||||
|
||||
def run(self):
|
||||
clip = ImageSequenceClip(self.list, fps=self.fps)
|
||||
clip.write_videofile(self.path) # to video
|
||||
self.trigger.emit()
|
||||
shutil.rmtree('temp')
|
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 745 B |
After Width: | Height: | Size: 843 B |
After Width: | Height: | Size: 548 B |
After Width: | Height: | Size: 564 B |
After Width: | Height: | Size: 1.3 KiB |
After Width: | Height: | Size: 24 KiB |
After Width: | Height: | Size: 20 KiB |