Gui Postprocessing with basic printing support
This commit is contained in:
@@ -20,9 +20,10 @@ class TeardownException(Exception):
|
|||||||
|
|
||||||
class Photobooth:
|
class Photobooth:
|
||||||
|
|
||||||
def __init__(self, config, camera, conn):
|
def __init__(self, config, camera, conn, queue):
|
||||||
|
|
||||||
self._conn = conn
|
self._conn = conn
|
||||||
|
self._queue = queue
|
||||||
|
|
||||||
self.initCamera(config, camera())
|
self.initCamera(config, camera())
|
||||||
self.initGpio(config)
|
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._app = QApplication(argv)
|
||||||
self._p = PyQt5MainWindow()
|
self._p = PyQt5MainWindow()
|
||||||
self._lastState = self.showStart
|
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 = PyQt5Receiver([camera_conn])
|
||||||
receiver.notify.connect(self.handleState)
|
receiver.notify.connect(self.handleState)
|
||||||
receiver.start()
|
receiver.start()
|
||||||
|
|
||||||
self._conn = camera_conn
|
self._conn = camera_conn
|
||||||
|
self._queue = worker_queue
|
||||||
|
|
||||||
self.showStart()
|
self.showStart()
|
||||||
|
|
||||||
@@ -134,9 +139,11 @@ class PyQt5Gui(Gui):
|
|||||||
elif isinstance(state, PictureState):
|
elif isinstance(state, PictureState):
|
||||||
img = ImageQt.ImageQt(state.picture)
|
img = ImageQt.ImageQt(state.picture)
|
||||||
self._p.setCentralWidget(PyQt5PictureMessage('', img))
|
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):
|
elif isinstance(state, TeardownState):
|
||||||
self._conn.send('teardown')
|
self._conn.send('teardown')
|
||||||
@@ -149,6 +156,14 @@ class PyQt5Gui(Gui):
|
|||||||
raise ValueError('Unknown state')
|
raise ValueError('Unknown state')
|
||||||
|
|
||||||
|
|
||||||
|
def postprocessPicture(self, picture):
|
||||||
|
|
||||||
|
for task in self._postprocessList:
|
||||||
|
task.do(self._p, picture)
|
||||||
|
|
||||||
|
self.sendAck()
|
||||||
|
|
||||||
|
|
||||||
def showStart(self):
|
def showStart(self):
|
||||||
|
|
||||||
self._p.handleKeypressEvent = lambda event : None
|
self._p.handleKeypressEvent = lambda event : None
|
||||||
|
|||||||
@@ -2,6 +2,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
|
||||||
|
from .GuiState import *
|
||||||
|
from .GuiPostprocess import *
|
||||||
|
|
||||||
|
|
||||||
# Available gui modules as tuples of (config name, module name, class name)
|
# Available gui modules as tuples of (config name, module name, class name)
|
||||||
modules = ( ('qt5', 'PyQt5Gui', 'PyQt5Gui'), )
|
modules = ( ('qt5', 'PyQt5Gui', 'PyQt5Gui'), )
|
||||||
|
|
||||||
@@ -13,151 +17,8 @@ class Gui:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
def run(self, send, recv):
|
def run(self, camera_conn, worker_queue):
|
||||||
|
|
||||||
raise NotImplementedError()
|
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'
|
__version__ = 'unknown'
|
||||||
|
|
||||||
import multiprocessing as mp
|
import multiprocessing as mp
|
||||||
import importlib
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from . import camera, gui
|
from . import camera, gui
|
||||||
from .Config import Config
|
from .Config import Config
|
||||||
from .Photobooth import Photobooth
|
from .Photobooth import Photobooth
|
||||||
|
from .util import lookup_and_import
|
||||||
|
|
||||||
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])
|
|
||||||
|
|
||||||
|
|
||||||
class CameraProcess(mp.Process):
|
class CameraProcess(mp.Process):
|
||||||
|
|
||||||
def __init__(self, config, conn):
|
def __init__(self, config, conn, worker_queue):
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.daemon = True
|
self.daemon = True
|
||||||
|
|
||||||
self.cfg = config
|
self.cfg = config
|
||||||
self.conn = conn
|
self.conn = conn
|
||||||
|
self.worker_queue = worker_queue
|
||||||
|
|
||||||
|
|
||||||
def run_camera(self):
|
def run_camera(self):
|
||||||
|
|
||||||
# while True:
|
|
||||||
try:
|
try:
|
||||||
cap = lookup_and_import(
|
cap = lookup_and_import(
|
||||||
camera.modules, self.cfg.get('Camera', 'module'), 'camera')
|
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()
|
return photobooth.run()
|
||||||
|
|
||||||
except BaseException as e:
|
except BaseException as e:
|
||||||
@@ -81,21 +63,39 @@ class CameraProcess(mp.Process):
|
|||||||
sys.exit(status_code)
|
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):
|
class GuiProcess(mp.Process):
|
||||||
|
|
||||||
def __init__(self, argv, config, conn):
|
def __init__(self, argv, config, conn, queue):
|
||||||
|
|
||||||
super().__init__()
|
super().__init__()
|
||||||
|
|
||||||
self.argv = argv
|
self.argv = argv
|
||||||
self.cfg = config
|
self.cfg = config
|
||||||
self.conn = conn
|
self.conn = conn
|
||||||
|
self.queue = queue
|
||||||
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
|
|
||||||
Gui = lookup_and_import(gui.modules, self.cfg.get('Gui', 'module'), 'gui')
|
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):
|
def run(argv):
|
||||||
@@ -105,19 +105,23 @@ def run(argv):
|
|||||||
config = Config('photobooth.cfg')
|
config = Config('photobooth.cfg')
|
||||||
|
|
||||||
gui_conn, camera_conn = mp.Pipe()
|
gui_conn, camera_conn = mp.Pipe()
|
||||||
|
worker_queue = mp.SimpleQueue()
|
||||||
|
|
||||||
camera_worker = CameraProcess(config, camera_conn)
|
camera_proc = CameraProcess(config, camera_conn, worker_queue)
|
||||||
camera_worker.start()
|
camera_proc.start()
|
||||||
|
|
||||||
gui_worker = GuiProcess(argv, config, gui_conn)
|
worker_proc = WorkerProcess(config, worker_queue)
|
||||||
gui_worker.start()
|
worker_proc.start()
|
||||||
|
|
||||||
|
gui_proc = GuiProcess(argv, config, gui_conn, worker_queue)
|
||||||
|
gui_proc.start()
|
||||||
|
|
||||||
gui_conn.close()
|
gui_conn.close()
|
||||||
camera_conn.close()
|
camera_conn.close()
|
||||||
|
|
||||||
gui_worker.join()
|
gui_proc.join()
|
||||||
camera_worker.join(5)
|
camera_proc.join(5)
|
||||||
return gui_worker.exitcode
|
return gui_proc.exitcode
|
||||||
|
|
||||||
|
|
||||||
def main(argv):
|
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