Last active
November 26, 2022 09:32
-
-
Save ssarangi/7e77dfe70a379ab24e06 to your computer and use it in GitHub Desktop.
Script for generating screenshots with PySide with area selection option
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
capture.py | |
A simple screen capture app using PySide ( or PyQt4 ) | |
#TODO: modifications required to run on Windows | |
Copyright Marc Robinson 2014 | |
''' | |
import time | |
import sys,os | |
import threading | |
import queue | |
import numpy | |
from PIL import Image | |
from images2gif import writeGif | |
from PySide.QtGui import QPixmap, QApplication, QMainWindow,QWidget,\ | |
QPushButton,QVBoxLayout,QPainter,QCursor,QSpinBox,\ | |
QLabel,QGridLayout,QLineEdit,QButtonGroup,QRadioButton, \ | |
QGroupBox,QLayout, QDialog | |
from PySide.QtCore import SIGNAL,Qt, QThread | |
class SelectedArea(QWidget): | |
def __init__(self): | |
QWidget.__init__(self,None,Qt.Window) | |
self.setWindowFlags(Qt.Window | Qt.WindowStaysOnTopHint | Qt.X11BypassWindowManagerHint | Qt.FramelessWindowHint ) | |
self.setStyleSheet("QWidget { background-color: rgba(255, 192, 64, 50%); \ | |
border: 1px solid rgb(255, 192, 64)}") | |
class TransWindow(QWidget): | |
def __init__(self): | |
QWidget.__init__(self,None,Qt.Window) | |
self.layout = QGridLayout() | |
self.setLayout(self.layout) | |
self.showMaximized() | |
self.activateWindow() | |
self.raise_() | |
self.setWindowFlags(Qt.Window | Qt.WindowStaysOnTopHint | Qt.X11BypassWindowManagerHint \ | |
| Qt.FramelessWindowHint ) | |
screenGeometry = QApplication.desktop().availableGeometry(); | |
self.setGeometry(screenGeometry) | |
self.setWindowOpacity(.8) | |
self.setStyleSheet("QMainWindow { background: 'black'}"); | |
def mousePressEvent(self, QMouseEvent): | |
self.hide() | |
xd = QApplication.desktop().screenGeometry().x() - QApplication.desktop().availableGeometry().x() | |
yd = QApplication.desktop().screenGeometry().y() - QApplication.desktop().availableGeometry().y() | |
self.pos = numpy.array([QMouseEvent.pos().x()-xd, | |
QMouseEvent.pos().y()-yd]) | |
self.emit(SIGNAL("mouse_press()")) | |
class SnapShots(QThread): | |
def __init__(self,main_window,fps=25): | |
QThread.__init__(self) | |
self.fps = fps | |
self.main_window = main_window | |
self.halt = False | |
self.queue = queue.Queue() | |
def run(self,fps=None): | |
if(fps!=None):self.fps=fps | |
period = 1.0/self.fps | |
while not (self.halt): | |
st = time.time() | |
while not self.queue.empty(): | |
pass | |
self.queue.put("capture") | |
self.emit(SIGNAL("capture()")) | |
td = time.time()-st | |
wait = period-td | |
if(wait>0):time.sleep(wait) | |
#empty the queue here (thread safe) | |
with self.queue.mutex: | |
self.queue.queue.clear() | |
class OptionsContainer(QWidget): | |
def __init__(self,main_window): | |
QWidget.__init__(self) | |
self.main_window = main_window | |
self.layout = QGridLayout() | |
self.setLayout(self.layout) | |
self.lr = numpy.zeros(2) | |
self.fps = QSpinBox() | |
self.fps.setValue(25) | |
self.fps.setMinimum(1) | |
self.fps.setMaximum(1000) | |
self.layout.addWidget(QLabel("FPS:"),10,10) | |
self.layout.addWidget(self.fps,10,11) | |
self.capture_area_group = QButtonGroup() | |
self.capture_area_fs = QRadioButton("Full Screen") | |
self.connect(self.capture_area_fs, SIGNAL("clicked()"),self.capture_area_change) | |
self.capture_area_fs.setChecked(True) | |
self.capture_area_sa = QRadioButton("Selected Area") | |
self.connect(self.capture_area_sa, SIGNAL("clicked()"),self.capture_area_change) | |
self.capture_area_group.addButton(self.capture_area_fs) | |
self.capture_area_group.addButton(self.capture_area_sa) | |
self.capture_area_group.setExclusive(True) | |
self.layout.addWidget(self.capture_area_fs,12,10) | |
self.layout.addWidget(self.capture_area_sa,12,11) | |
self.sa_group = QGroupBox() | |
self.sa_grid = QGridLayout() | |
self.sa_group.setLayout(self.sa_grid) | |
self.sa_ul_bt = QPushButton("Select Upper Left") | |
self.connect(self.sa_ul_bt, SIGNAL("clicked()"), self.select_ul) | |
self.sa_lr_bt = QPushButton("Select Lower Right") | |
self.connect(self.sa_lr_bt, SIGNAL("clicked()"), self.select_lr) | |
self.sa_x = QSpinBox() | |
self.sa_y = QSpinBox() | |
self.sa_w = QSpinBox() | |
self.sa_h = QSpinBox() | |
for sb in [self.sa_h,self.sa_w,self.sa_x,self.sa_y]: | |
sb.setMaximum(999999) | |
sb.setMinimum(0) | |
self.sa_grid.addWidget(self.sa_ul_bt,14,10,1,1) | |
self.sa_grid.addWidget(self.sa_lr_bt,15,10,1,1) | |
self.sa_grid.addWidget(QLabel("x"),14,11,1,1) | |
self.sa_grid.addWidget(self.sa_x,14,12,1,1) | |
self.sa_grid.addWidget(QLabel("y"),15,11,1,1) | |
self.sa_grid.addWidget(self.sa_y,15,12,1,1) | |
self.sa_grid.addWidget(QLabel("w"),16,11,1,1) | |
self.sa_grid.addWidget(self.sa_w,16,12,1,1) | |
self.sa_grid.addWidget(QLabel("h"),17,11,1,1) | |
self.sa_grid.addWidget(self.sa_h,17,12,1,1) | |
self.sa_show_bt = QPushButton("Show Area") | |
self.sa_show_bt.setCheckable(True) | |
self.connect(self.sa_show_bt, SIGNAL("clicked()"), self.show_selected_area) | |
self.sa_grid.addWidget(self.sa_show_bt,18,10,1,10) | |
self.sa_group.hide() | |
self.layout.addWidget(self.sa_group,14,10,1,10) | |
self.capture_delay = QSpinBox() | |
self.capture_delay.setMinimum(0) | |
self.capture_delay.setMaximum(10000) | |
self.layout.addWidget(QLabel("Capture Delay"),18,10,1,1) | |
self.layout.addWidget(self.capture_delay,18,11,1,1) | |
self.capture_bt = QPushButton("Capture") | |
self.stop_capture_bt = QPushButton("Stop") | |
self.stop_capture_bt.hide() | |
self.layout.addWidget(self.capture_bt,20,10,1,10) | |
self.layout.addWidget(self.stop_capture_bt,30,10,1,10) | |
self.capture_name = QLineEdit() | |
self.capture_name.setText("capture") | |
self.layout.addWidget(QLabel("Capture Name:"),40,10) | |
self.layout.addWidget(self.capture_name,50,10,1,10) | |
self.encode_bt = QPushButton("Encode Gif") | |
self.layout.addWidget(self.encode_bt,60,10,1,10) | |
self.open_dir_bt = QPushButton("Open Directory") | |
self.layout.addWidget(self.open_dir_bt,80,10,1,10) | |
self.connect(self.open_dir_bt, SIGNAL("clicked()"),self.open_cwd) | |
self.selected_area = SelectedArea() | |
def show_selected_area(self): | |
x = self.sa_x.value() | |
y = self.sa_y.value() | |
w = self.sa_w.value() | |
h = self.sa_h.value() | |
self.selected_area.setGeometry(x,y,w,h) | |
self.selected_area.activateWindow() | |
self.selected_area.raise_() | |
if(self.sa_show_bt.isChecked()): | |
self.selected_area.show() | |
else:self.selected_area.hide() | |
def select_ul(self): | |
self.clicked = False | |
self.tw = TransWindow() | |
self.tw.mouse_press = False | |
self.tw.show() | |
self.connect(self.tw, SIGNAL("mouse_press()"),self.set_ul) | |
def select_lr(self): | |
self.clicked = False | |
self.tw = TransWindow() | |
self.tw.mouse_press = False | |
self.tw.show() | |
self.connect(self.tw, SIGNAL("mouse_press()"),self.set_lr) | |
def set_ul(self): | |
self.sa_x.setValue( self.tw.pos[0]) | |
self.sa_y.setValue( self.tw.pos[1]) | |
self.sa_w.setValue( self.lr[0] - self.sa_x.value()) | |
self.sa_h.setValue( self.lr[1] - self.sa_y.value()) | |
self.show_selected_area() | |
def set_lr(self): | |
self.lr = numpy.array([self.tw.pos[0],self.tw.pos[1]]) | |
self.sa_w.setValue( self.tw.pos[0] - self.sa_x.value()) | |
self.sa_h.setValue( self.tw.pos[1] - self.sa_y.value()) | |
self.show_selected_area() | |
def capture_area_change(self): | |
if(self.capture_area_fs.isChecked()): | |
self.sa_group.hide() | |
else: | |
self.sa_group.show() | |
self.adjustSize() | |
self.main_window.adjustSize() | |
def open_cwd(self): | |
#will need to detect os and change accordingly | |
os.system("open {}".format(os.getcwd())) | |
class MainWindow(QMainWindow): | |
def __init__(self): | |
QMainWindow.__init__(self,None,Qt.WindowStaysOnTopHint) | |
self.options = OptionsContainer(self) | |
self.setCentralWidget(self.options) | |
self.arrow_icon = os.path.abspath(os.path.dirname(__file__)+"/cursor3.png") | |
self.connect(self.options.capture_bt, SIGNAL("clicked()"),self.start_capture) | |
self.connect(self.options.stop_capture_bt, SIGNAL("clicked()"),self.stop_capture) | |
self.connect(self.options.encode_bt, SIGNAL("clicked()"),self.encode_gif) | |
self.snap_shots = SnapShots(self,fps = self.options.fps.value()) | |
self.connect(self.snap_shots, SIGNAL("capture()"),self.capture) | |
def remove_all_snap_shots(self): | |
try: | |
# os.system("rm tmp_*.jpg") | |
pass | |
except: | |
pass | |
def start_capture(self): | |
time.sleep(self.options.capture_delay.value()) | |
self.UID = numpy.random.randint(0,9999999) | |
self.remove_all_snap_shots() | |
self.capture_count = 0 | |
self.snap_shots.halt=False | |
self.snap_shots.fps = self.options.fps.value() | |
self.snap_shots.start() | |
self.options.capture_bt.hide() | |
self.options.encode_bt.setEnabled(False) | |
self.options.stop_capture_bt.show() | |
self.start_capture_time = time.time() | |
def stop_capture(self): | |
self.snap_shots.halt=True | |
#self.snap_shots.wait() | |
self.options.stop_capture_bt.hide() | |
self.options.capture_bt.show() | |
self.options.encode_bt.setEnabled(True) | |
self.stop_capture_time = time.time() | |
def capture(self): | |
app.processEvents() | |
if not self.snap_shots.queue.empty(): | |
self.snap_shots.queue.get(0) | |
arrow = QPixmap(self.arrow_icon); | |
self.px = QPixmap.grabWindow(QApplication.desktop().winId()) | |
painter = QPainter(self.px) | |
painter.drawPixmap(QCursor.pos(), arrow) | |
if(self.options.capture_area_sa.isChecked()): | |
self.px2 = self.px.copy(self.options.sa_x.value(), | |
self.options.sa_y.value(), | |
self.options.sa_w.value(), | |
self.options.sa_h.value()) | |
else: | |
self.px2 = self.px | |
dir = self.options.capture_name.text() | |
file_postfix = "{0:03}".format(self.capture_count) | |
self.px2.save((dir + '/screenshot_%s.png' % (file_postfix)), 'png') | |
self.capture_count+=1 | |
def encode_gif(self): | |
# Get the directory name | |
frames = [] | |
dir = self.options.capture_name.text() | |
import os, re | |
rex = re.compile("screenshot_([0-9]+).png") | |
for f in os.listdir(dir): | |
m = re.search(rex, f) | |
if m: | |
frames.append((int(m.group(1)), dir + "/" + f)) | |
frames.sort() | |
images = [] | |
for id, frame in frames: | |
im = Image.open(frame) | |
images.append(im) | |
writeGif(dir + '.gif', images, duration=0.5, dither=0) | |
def mousePressEvent(self, QMouseEvent): | |
pass | |
def keyPressEvent(self, event): | |
if event.key() == Qt.Key_Q: | |
sys.exit() | |
if __name__ == '__main__': | |
global app | |
app = QApplication(sys.argv) | |
window = MainWindow() | |
window.show() | |
try: | |
sys.exit(app.exec_()) | |
except SystemExit as e: | |
if e.code != 0: | |
raise() | |
os._exit(0) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment