Gui Postprocessing with basic printing support
This commit is contained in:
@@ -20,9 +20,10 @@ class TeardownException(Exception):
|
||||
|
||||
class Photobooth:
|
||||
|
||||
def __init__(self, config, camera, conn):
|
||||
def __init__(self, config, camera, conn, queue):
|
||||
|
||||
self._conn = conn
|
||||
self._queue = queue
|
||||
|
||||
self.initCamera(config, camera())
|
||||
self.initGpio(config)
|
||||
|
||||
40
photobooth/gui/GuiPostprocess.py
Normal file
40
photobooth/gui/GuiPostprocess.py
Normal file
@@ -0,0 +1,40 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from .. import printer
|
||||
from ..util import lookup_and_import
|
||||
|
||||
from PyQt5.QtWidgets import QMessageBox
|
||||
|
||||
class GuiPostprocess:
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
assert not kwargs
|
||||
|
||||
|
||||
def do(self, parent, picture):
|
||||
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
|
||||
|
||||
class PrintPostprocess(GuiPostprocess):
|
||||
|
||||
def __init__(self, printer_module, page_size, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
Printer = lookup_and_import(printer.modules, printer_module, 'printer')
|
||||
self._printer = Printer(page_size, True)
|
||||
|
||||
|
||||
def do(self, parent, picture):
|
||||
|
||||
reply = QMessageBox.question(parent, 'Print?',
|
||||
'Do you want to print the picture?',
|
||||
QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
|
||||
|
||||
if reply == QMessageBox.Yes:
|
||||
self._printer.print(picture)
|
||||
146
photobooth/gui/GuiState.py
Normal file
146
photobooth/gui/GuiState.py
Normal file
@@ -0,0 +1,146 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
class GuiState:
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
assert not kwargs
|
||||
|
||||
|
||||
|
||||
class ErrorState(GuiState):
|
||||
|
||||
def __init__(self, title, message, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.title = title
|
||||
self.message = message
|
||||
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
|
||||
return self._title
|
||||
|
||||
|
||||
@title.setter
|
||||
def title(self, title):
|
||||
|
||||
self._title = title
|
||||
|
||||
|
||||
@property
|
||||
def message(self):
|
||||
|
||||
return self._message
|
||||
|
||||
|
||||
@message.setter
|
||||
def message(self, message):
|
||||
|
||||
self._message = message
|
||||
|
||||
|
||||
class IdleState(GuiState):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
|
||||
class PictureState(GuiState):
|
||||
|
||||
def __init__(self, picture, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.picture = picture
|
||||
|
||||
|
||||
@property
|
||||
def picture(self):
|
||||
|
||||
return self._pic
|
||||
|
||||
|
||||
@picture.setter
|
||||
def picture(self, picture):
|
||||
|
||||
self._pic = picture
|
||||
|
||||
|
||||
class MessageState(GuiState):
|
||||
|
||||
def __init__(self, message, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.message = message
|
||||
|
||||
|
||||
@property
|
||||
def message(self):
|
||||
|
||||
return self._msg
|
||||
|
||||
|
||||
@message.setter
|
||||
def message(self, message):
|
||||
|
||||
if not isinstance(message, str):
|
||||
raise ValueError('Message must be a string')
|
||||
|
||||
self._msg = message
|
||||
|
||||
|
||||
|
||||
class TriggerState(GuiState):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class GreeterState(GuiState):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class PoseState(GuiState):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class AssembleState(GuiState):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class CountdownState(GuiState):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class PreviewState(PictureState):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
class TeardownState(GuiState):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
@@ -33,17 +33,22 @@ class PyQt5Gui(Gui):
|
||||
self._app = QApplication(argv)
|
||||
self._p = PyQt5MainWindow()
|
||||
self._lastState = self.showStart
|
||||
self._printer = Printer((cfg.getInt('Printer', 'width'),
|
||||
cfg.getInt('Printer', 'height')), True)
|
||||
|
||||
self._postprocessList = []
|
||||
|
||||
if cfg.getBool('Printer', 'enable'):
|
||||
self._postprocessList.append( PrintPostprocess( cfg.get('Printer', 'module'),
|
||||
(cfg.getInt('Printer', 'width'), cfg.getInt('Printer', 'height')) ) )
|
||||
|
||||
|
||||
def run(self, camera_conn):
|
||||
def run(self, camera_conn, worker_queue):
|
||||
|
||||
receiver = PyQt5Receiver([camera_conn])
|
||||
receiver.notify.connect(self.handleState)
|
||||
receiver.start()
|
||||
|
||||
self._conn = camera_conn
|
||||
self._queue = worker_queue
|
||||
|
||||
self.showStart()
|
||||
|
||||
@@ -134,9 +139,11 @@ class PyQt5Gui(Gui):
|
||||
elif isinstance(state, PictureState):
|
||||
img = ImageQt.ImageQt(state.picture)
|
||||
self._p.setCentralWidget(PyQt5PictureMessage('', img))
|
||||
QTimer.singleShot(cfg.getInt('Photobooth', 'display_time') * 1000, lambda : self.sendAck())
|
||||
# QTimer.singleShot(cfg.getInt('Photobooth', 'display_time') * 1000, self.sendAck)
|
||||
QTimer.singleShot(cfg.getInt('Photobooth', 'display_time') * 1000,
|
||||
lambda : self.postprocessPicture(state.picture))
|
||||
|
||||
self._printer.print(state.picture)
|
||||
# self._printer.print(state.picture)
|
||||
|
||||
elif isinstance(state, TeardownState):
|
||||
self._conn.send('teardown')
|
||||
@@ -149,6 +156,14 @@ class PyQt5Gui(Gui):
|
||||
raise ValueError('Unknown state')
|
||||
|
||||
|
||||
def postprocessPicture(self, picture):
|
||||
|
||||
for task in self._postprocessList:
|
||||
task.do(self._p, picture)
|
||||
|
||||
self.sendAck()
|
||||
|
||||
|
||||
def showStart(self):
|
||||
|
||||
self._p.handleKeypressEvent = lambda event : None
|
||||
|
||||
@@ -2,6 +2,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
from .GuiState import *
|
||||
from .GuiPostprocess import *
|
||||
|
||||
|
||||
# Available gui modules as tuples of (config name, module name, class name)
|
||||
modules = ( ('qt5', 'PyQt5Gui', 'PyQt5Gui'), )
|
||||
|
||||
@@ -13,151 +17,8 @@ class Gui:
|
||||
pass
|
||||
|
||||
|
||||
def run(self, send, recv):
|
||||
def run(self, camera_conn, worker_queue):
|
||||
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
|
||||
class GuiState:
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
assert not kwargs
|
||||
|
||||
|
||||
|
||||
class ErrorState(GuiState):
|
||||
|
||||
def __init__(self, title, message, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.title = title
|
||||
self.message = message
|
||||
|
||||
|
||||
@property
|
||||
def title(self):
|
||||
|
||||
return self._title
|
||||
|
||||
|
||||
@title.setter
|
||||
def title(self, title):
|
||||
|
||||
self._title = title
|
||||
|
||||
|
||||
@property
|
||||
def message(self):
|
||||
|
||||
return self._message
|
||||
|
||||
|
||||
@message.setter
|
||||
def message(self, message):
|
||||
|
||||
self._message = message
|
||||
|
||||
|
||||
class IdleState(GuiState):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
|
||||
class PictureState(GuiState):
|
||||
|
||||
def __init__(self, picture, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.picture = picture
|
||||
|
||||
|
||||
@property
|
||||
def picture(self):
|
||||
|
||||
return self._pic
|
||||
|
||||
|
||||
@picture.setter
|
||||
def picture(self, picture):
|
||||
|
||||
self._pic = picture
|
||||
|
||||
|
||||
class MessageState(GuiState):
|
||||
|
||||
def __init__(self, message, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
self.message = message
|
||||
|
||||
|
||||
@property
|
||||
def message(self):
|
||||
|
||||
return self._msg
|
||||
|
||||
|
||||
@message.setter
|
||||
def message(self, message):
|
||||
|
||||
if not isinstance(message, str):
|
||||
raise ValueError('Message must be a string')
|
||||
|
||||
self._msg = message
|
||||
|
||||
|
||||
|
||||
class TriggerState(GuiState):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class GreeterState(GuiState):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class PoseState(GuiState):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class AssembleState(GuiState):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class CountdownState(GuiState):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
|
||||
class PreviewState(PictureState):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
class TeardownState(GuiState):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
|
||||
super().__init__(**kwargs)
|
||||
|
||||
@@ -8,51 +8,33 @@ except DistributionNotFound:
|
||||
__version__ = 'unknown'
|
||||
|
||||
import multiprocessing as mp
|
||||
import importlib
|
||||
import sys
|
||||
|
||||
from . import camera, gui
|
||||
from .Config import Config
|
||||
from .Photobooth import Photobooth
|
||||
|
||||
|
||||
def lookup_and_import(module_list, name, package=None):
|
||||
|
||||
result = next(((mod_name, class_name)
|
||||
for config_name, mod_name, class_name in module_list
|
||||
if name == config_name), None)
|
||||
|
||||
if package == None:
|
||||
import_module = importlib.import_module('photobooth.' + result[0])
|
||||
else:
|
||||
import_module = importlib.import_module(
|
||||
'photobooth.' + package + '.' + result[0])
|
||||
|
||||
if result[1] == None:
|
||||
return import_module
|
||||
else:
|
||||
return getattr(import_module, result[1])
|
||||
|
||||
from .util import lookup_and_import
|
||||
|
||||
class CameraProcess(mp.Process):
|
||||
|
||||
def __init__(self, config, conn):
|
||||
def __init__(self, config, conn, worker_queue):
|
||||
|
||||
super().__init__()
|
||||
self.daemon = True
|
||||
|
||||
self.cfg = config
|
||||
self.conn = conn
|
||||
self.worker_queue = worker_queue
|
||||
|
||||
|
||||
def run_camera(self):
|
||||
|
||||
# while True:
|
||||
try:
|
||||
cap = lookup_and_import(
|
||||
camera.modules, self.cfg.get('Camera', 'module'), 'camera')
|
||||
|
||||
photobooth = Photobooth(self.cfg, cap, self.conn)
|
||||
photobooth = Photobooth(
|
||||
self.cfg, cap, self.conn, self.worker_queue)
|
||||
return photobooth.run()
|
||||
|
||||
except BaseException as e:
|
||||
@@ -81,21 +63,39 @@ class CameraProcess(mp.Process):
|
||||
sys.exit(status_code)
|
||||
|
||||
|
||||
class WorkerProcess(mp.Process):
|
||||
|
||||
def __init__(self, config, queue):
|
||||
|
||||
super().__init__()
|
||||
self.daemon = True
|
||||
|
||||
self.cfg = config
|
||||
self.queue = queue
|
||||
|
||||
|
||||
def run(self):
|
||||
|
||||
print('Started Worker')
|
||||
print('Exit Worker')
|
||||
|
||||
|
||||
class GuiProcess(mp.Process):
|
||||
|
||||
def __init__(self, argv, config, conn):
|
||||
def __init__(self, argv, config, conn, queue):
|
||||
|
||||
super().__init__()
|
||||
|
||||
self.argv = argv
|
||||
self.cfg = config
|
||||
self.conn = conn
|
||||
self.queue = queue
|
||||
|
||||
|
||||
def run(self):
|
||||
|
||||
Gui = lookup_and_import(gui.modules, self.cfg.get('Gui', 'module'), 'gui')
|
||||
sys.exit(Gui(self.argv, self.cfg).run(self.conn))
|
||||
sys.exit(Gui(self.argv, self.cfg).run(self.conn, self.queue))
|
||||
|
||||
|
||||
def run(argv):
|
||||
@@ -105,19 +105,23 @@ def run(argv):
|
||||
config = Config('photobooth.cfg')
|
||||
|
||||
gui_conn, camera_conn = mp.Pipe()
|
||||
worker_queue = mp.SimpleQueue()
|
||||
|
||||
camera_worker = CameraProcess(config, camera_conn)
|
||||
camera_worker.start()
|
||||
camera_proc = CameraProcess(config, camera_conn, worker_queue)
|
||||
camera_proc.start()
|
||||
|
||||
gui_worker = GuiProcess(argv, config, gui_conn)
|
||||
gui_worker.start()
|
||||
worker_proc = WorkerProcess(config, worker_queue)
|
||||
worker_proc.start()
|
||||
|
||||
gui_proc = GuiProcess(argv, config, gui_conn, worker_queue)
|
||||
gui_proc.start()
|
||||
|
||||
gui_conn.close()
|
||||
camera_conn.close()
|
||||
|
||||
gui_worker.join()
|
||||
camera_worker.join(5)
|
||||
return gui_worker.exitcode
|
||||
gui_proc.join()
|
||||
camera_proc.join(5)
|
||||
return gui_proc.exitcode
|
||||
|
||||
|
||||
def main(argv):
|
||||
|
||||
23
photobooth/util.py
Normal file
23
photobooth/util.py
Normal file
@@ -0,0 +1,23 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
|
||||
import importlib
|
||||
|
||||
|
||||
def lookup_and_import(module_list, name, package=None):
|
||||
|
||||
result = next(((mod_name, class_name)
|
||||
for config_name, mod_name, class_name in module_list
|
||||
if name == config_name), None)
|
||||
|
||||
if package == None:
|
||||
import_module = importlib.import_module('photobooth.' + result[0])
|
||||
else:
|
||||
import_module = importlib.import_module(
|
||||
'photobooth.' + package + '.' + result[0])
|
||||
|
||||
if result[1] == None:
|
||||
return import_module
|
||||
else:
|
||||
return getattr(import_module, result[1])
|
||||
Reference in New Issue
Block a user