@ -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 |