flake8 compliance (except for PyQt5Gui)

This commit is contained in:
Balthasar Reuter
2018-05-24 23:25:32 +02:00
parent e02451a7fd
commit d79317bb79
22 changed files with 303 additions and 413 deletions

View File

@@ -1,7 +1,9 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import configparser, os, logging import configparser
import logging
import os
class Config: class Config:
@@ -14,59 +16,49 @@ class Config:
self.defaults() self.defaults()
self.read() self.read()
@property @property
def filename(self): def filename(self):
return self._filename return self._filename
@filename.setter @filename.setter
def filename(self, value): def filename(self, value):
self._filename = value self._filename = value
def defaults(self): def defaults(self):
filename = os.path.join(os.path.dirname(__file__), 'defaults.cfg') filename = os.path.join(os.path.dirname(__file__), 'defaults.cfg')
logging.info('Reading config file "%s"', filename) logging.info('Reading config file "%s"', filename)
self._cfg.read(filename) self._cfg.read(filename)
def read(self): def read(self):
logging.info('Reading config file "%s"', self._filename) logging.info('Reading config file "%s"', self._filename)
self._cfg.read(self._filename) self._cfg.read(self._filename)
def write(self): def write(self):
logging.info('Writing config file "%s"', self._filename) logging.info('Writing config file "%s"', self._filename)
with open(self._filename, 'w') as configfile: with open(self._filename, 'w') as configfile:
self._cfg.write(configfile) self._cfg.write(configfile)
def get(self, section, key): def get(self, section, key):
return self._cfg[section][key] return self._cfg[section][key]
def getInt(self, section, key): def getInt(self, section, key):
return self._cfg.getint(section, key) return self._cfg.getint(section, key)
def getFloat(self, section, key): def getFloat(self, section, key):
return self._cfg.getfloat(section, key) return self._cfg.getfloat(section, key)
def getBool(self, section, key): def getBool(self, section, key):
return self._cfg.getboolean(section, key) return self._cfg.getboolean(section, key)
def set(self, section, key, value): def set(self, section, key, value):
self._cfg[section][key] = value self._cfg[section][key] = value

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from gpiozero import LED, Button from gpiozero import LED, Button
class Gpio: class Gpio:
@@ -10,29 +11,24 @@ class Gpio:
self._buttons = [] self._buttons = []
self._lamps = [] self._lamps = []
def setButton(self, bcm_pin, handler): def setButton(self, bcm_pin, handler):
self._buttons.append(Button(bcm_pin)) self._buttons.append(Button(bcm_pin))
self._buttons[-1].when_pressed = handler self._buttons[-1].when_pressed = handler
def setLamp(self, bcm_pin): def setLamp(self, bcm_pin):
self._lamps.append(LED(bcm_pin)) self._lamps.append(LED(bcm_pin))
return len(self._lamps) - 1 return len(self._lamps) - 1
def lampOn(self, index): def lampOn(self, index):
self._lamps[index].on() self._lamps[index].on()
def lampOff(self, index): def lampOff(self, index):
self._lamps[index].off() self._lamps[index].off()
def lampToggle(self, index): def lampToggle(self, index):
self._lamps[index].toggle() self._lamps[index].toggle()

View File

@@ -33,46 +33,43 @@ class Photobooth:
self.triggerOff() self.triggerOff()
def initCamera(self, config, camera): def initCamera(self, config, camera):
self._cap = camera self._cap = camera
self._pic_dims = PictureDimensions(config, self._cap.getPicture().size) self._pic_dims = PictureDimensions(config, self._cap.getPicture().size)
if ( config.getBool('Photobooth', 'show_preview') if (config.getBool('Photobooth', 'show_preview')
and self._cap.hasPreview ): and self._cap.hasPreview):
logging.info('Countdown with preview activated') logging.info('Countdown with preview activated')
self._show_counter = self.showCounterPreview self._show_counter = self.showCounterPreview
else: else:
logging.info('Countdown without preview activated') logging.info('Countdown without preview activated')
self._show_counter = self.showCounterNoPreview self._show_counter = self.showCounterNoPreview
def initGpio(self, config): def initGpio(self, config):
if config.getBool('Gpio', 'enable'): if config.getBool('Gpio', 'enable'):
lamp_pin = config.getInt('Gpio', 'lamp_pin') lamp_pin = config.getInt('Gpio', 'lamp_pin')
trigger_pin = config.getInt('Gpio', 'trigger_pin') trigger_pin = config.getInt('Gpio', 'trigger_pin')
exit_pin = config.getInt('Gpio', 'exit_pin') exit_pin = config.getInt('Gpio', 'exit_pin')
logging.info('GPIO enabled (lamp_pin=%d, trigger_pin=%d, exit_pin=%d)', logging.info(('GPIO enabled (lamp_pin=%d, trigger_pin=%d, '
lamp_pin, trigger_pin, exit_pin) 'exit_pin=%d)'), lamp_pin, trigger_pin, exit_pin)
from Gpio import Gpio from Gpio import Gpio
self._gpio = Gpio() self._gpio = Gpio()
lamp = self._gpio.setLamp(lamp_pin) lamp = self._gpio.setLamp(lamp_pin)
self._lampOn = lambda : self._gpio.lampOn(lamp) self._lampOn = lambda: self._gpio.lampOn(lamp)
self._lampOff = lambda : self._gpio.lampOff(lamp) self._lampOff = lambda: self._gpio.lampOff(lamp)
self._gpio.setButton(trigger_pin, self.gpioTrigger) self._gpio.setButton(trigger_pin, self.gpioTrigger)
self._gpio.setButton(exit_pin, self.gpioExit) self._gpio.setButton(exit_pin, self.gpioExit)
else: else:
logging.info('GPIO disabled') logging.info('GPIO disabled')
self._lampOn = lambda : None self._lampOn = lambda: None
self._lampOff = lambda : None self._lampOff = lambda: None
def teardown(self): def teardown(self):
@@ -80,7 +77,6 @@ class Photobooth:
self.triggerOff() self.triggerOff()
self.setCameraIdle() self.setCameraIdle()
def recvEvent(self, expected): def recvEvent(self, expected):
event = self._conn.recv() event = self._conn.recv()
@@ -93,7 +89,6 @@ class Photobooth:
return event_idx return event_idx
def recvAck(self): def recvAck(self):
events = ['ack', 'cancel', 'teardown'] events = ['ack', 'cancel', 'teardown']
@@ -102,7 +97,6 @@ class Photobooth:
logging.info('Teardown of camera requested') logging.info('Teardown of camera requested')
raise TeardownException() raise TeardownException()
def recvTriggered(self): def recvTriggered(self):
events = ['triggered', 'teardown'] events = ['triggered', 'teardown']
@@ -111,20 +105,17 @@ class Photobooth:
logging.info('Teardown of camera requested') logging.info('Teardown of camera requested')
raise TeardownException() raise TeardownException()
@property @property
def showCounter(self): def showCounter(self):
return self._show_counter return self._show_counter
def initRun(self): def initRun(self):
self.setCameraIdle() self.setCameraIdle()
self._conn.send(gui.IdleState()) self._conn.send(gui.IdleState())
self.triggerOn() self.triggerOn()
def run(self): def run(self):
self.initRun() self.initRun()
@@ -140,47 +131,41 @@ class Photobooth:
self.trigger() self.trigger()
except RuntimeError as e: except RuntimeError as e:
logging.error('Camera error: %s', str(e)) logging.error('Camera error: %s', str(e))
self._conn.send( gui.ErrorState('Camera error', str(e)) ) self._conn.send(gui.ErrorState('Camera error', str(e)))
self.recvAck() self.recvAck()
except TeardownException: except TeardownException:
self.teardown() self.teardown()
return 123 return 123
def setCameraActive(self): def setCameraActive(self):
self._cap.setActive() self._cap.setActive()
def setCameraIdle(self): def setCameraIdle(self):
if self._cap.hasIdle: if self._cap.hasIdle:
self._cap.setIdle() self._cap.setIdle()
def showCounterPreview(self): def showCounterPreview(self):
self._conn.send(gui.CountdownState()) self._conn.send(gui.CountdownState())
while not self._conn.poll(): while not self._conn.poll():
self._conn.send( picture = ImageOps.mirror(self._cap.getPreview())
gui.PreviewState(picture = ImageOps.mirror(self._cap.getPreview())) ) self._conn.send(gui.PreviewState(picture=picture))
self.recvAck() self.recvAck()
def showCounterNoPreview(self): def showCounterNoPreview(self):
self._conn.send(gui.CountdownState()) self._conn.send(gui.CountdownState())
self.recvAck() self.recvAck()
def showPose(self): def showPose(self):
self._conn.send(gui.PoseState()) self._conn.send(gui.PoseState())
def captureSinglePicture(self): def captureSinglePicture(self):
self.showCounter() self.showCounter()
@@ -190,29 +175,26 @@ class Photobooth:
self.setCameraActive() self.setCameraActive()
return picture return picture
def capturePictures(self): def capturePictures(self):
return [ self.captureSinglePicture() for _ in range(self._pic_dims.totalNumPictures) ] return [self.captureSinglePicture()
for _ in range(self._pic_dims.totalNumPictures)]
def assemblePictures(self, pictures): def assemblePictures(self, pictures):
output_image = Image.new('RGB', self._pic_dims.outputSize, (255, 255, 255)) image = Image.new('RGB', self._pic_dims.outputSize, (255, 255, 255))
for i in range(self._pic_dims.totalNumPictures): for i in range(self._pic_dims.totalNumPictures):
output_image.paste(pictures[i].resize(self._pic_dims.thumbnailSize), image.paste(pictures[i].resize(self._pic_dims.thumbnailSize),
self._pic_dims.thumbnailOffset[i]) self._pic_dims.thumbnailOffset[i])
return output_image
return image
def enqueueWorkerTasks(self, picture): def enqueueWorkerTasks(self, picture):
for task in self._worker_list: for task in self._worker_list:
self._queue.put(task.get(picture)) self._queue.put(task.get(picture))
def trigger(self): def trigger(self):
logging.info('Photobooth triggered') logging.info('Photobooth triggered')
@@ -228,7 +210,7 @@ class Photobooth:
img = self.assemblePictures(pics) img = self.assemblePictures(pics)
self._conn.send(gui.PictureState(img)) self._conn.send(gui.PictureState(img))
self.enqueueWorkerTasks(img) self.enqueueWorkerTasks(img)
self.setCameraIdle() self.setCameraIdle()
@@ -237,24 +219,20 @@ class Photobooth:
self._conn.send(gui.IdleState()) self._conn.send(gui.IdleState())
self.triggerOn() self.triggerOn()
def gpioTrigger(self): def gpioTrigger(self):
self._gpioTrigger() self._gpioTrigger()
def gpioExit(self): def gpioExit(self):
self._conn.send(gui.TeardownState()) self._conn.send(gui.TeardownState())
def triggerOff(self): def triggerOff(self):
self._lampOff() self._lampOff()
self._gpioTrigger = lambda : None self._gpioTrigger = lambda: None
def triggerOn(self): def triggerOn(self):
self._lampOn() self._lampOn()
self._gpioTrigger = lambda : self._conn.send(gui.TriggerState()) self._gpioTrigger = lambda: self._conn.send(gui.TriggerState())

View File

@@ -1,51 +1,50 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
class PictureDimensions: class PictureDimensions:
def __init__(self, config, capture_size): def __init__(self, config, capture_size):
self._num_pictures = ( config.getInt('Picture', 'num_x') , self._num_pictures = (config.getInt('Picture', 'num_x'),
config.getInt('Picture', 'num_y') ) config.getInt('Picture', 'num_y'))
self._capture_size = capture_size self._capture_size = capture_size
self._output_size = ( config.getInt('Picture', 'size_x') , self._output_size = (config.getInt('Picture', 'size_x'),
config.getInt('Picture', 'size_y') ) config.getInt('Picture', 'size_y'))
self._min_distance = ( config.getInt('Picture', 'min_dist_x') , self._min_distance = (config.getInt('Picture', 'min_dist_x'),
config.getInt('Picture', 'min_dist_y') ) config.getInt('Picture', 'min_dist_y'))
self.computeThumbnailDimensions() self.computeThumbnailDimensions()
def computeThumbnailDimensions(self): def computeThumbnailDimensions(self):
resize_factor = min( ( ( resize_factor = min((((self.outputSize[i] - (self.numPictures[i] + 1) *
( self.outputSize[i] - (self.numPictures[i] + 1) * self.minDistance[i] ) / self.minDistance[i]) /
( self.numPictures[i] * self.captureSize[i]) ) for i in range(2) ) ) (self.numPictures[i] * self.captureSize[i]))
for i in range(2)))
self._thumb_size = tuple( int(self.captureSize[i] * resize_factor) self._thumb_size = tuple(int(self.captureSize[i] * resize_factor)
for i in range(2) ) for i in range(2))
output_picture_dist = tuple( ( self.outputSize[i] - self.numPictures[i] * thumb_dist = tuple((self.outputSize[i] - self.numPictures[i] *
self.thumbnailSize[i] ) // (self.numPictures[i] + 1) self.thumbnailSize[i]) // (self.numPictures[i] + 1)
for i in range(2) ) for i in range(2))
self._thumb_offsets = [] self._thumb_offsets = []
for i in range(self.totalNumPictures): for i in range(self.totalNumPictures):
pos = (i % self.numPictures[0], i // self.numPictures[0]) pos = (i % self.numPictures[0], i // self.numPictures[0])
self._thumb_offsets.append( tuple( self._thumb_offsets.append(tuple((pos[j] + 1) * thumb_dist[j] +
(pos[j] + 1) * output_picture_dist[j] + pos[j] * self.thumbnailSize[j]
pos[j] * self.thumbnailSize[j] for j in range(2) ) ) for j in range(2)))
@property @property
def numPictures(self): def numPictures(self):
return self._num_pictures return self._num_pictures
@property @property
def totalNumPictures(self): def totalNumPictures(self):
@@ -56,25 +55,21 @@ class PictureDimensions:
return self._capture_size return self._capture_size
@property @property
def outputSize(self): def outputSize(self):
return self._output_size return self._output_size
@property @property
def minDistance(self): def minDistance(self):
return self._min_distance return self._min_distance
@property @property
def thumbnailSize(self): def thumbnailSize(self):
return self._thumb_size return self._thumb_size
@property @property
def thumbnailOffset(self): def thumbnailOffset(self):

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os, logging import logging
import os
from glob import glob from glob import glob
@@ -30,10 +31,10 @@ class PictureList:
self.findExistingFiles() self.findExistingFiles()
def findExistingFiles(self): def findExistingFiles(self):
"""Count number of existing files matchin the given basename
# Find existing files """
# Find existing files
count_pattern = '[0-9]' * self.count_width count_pattern = '[0-9]' * self.count_width
pictures = glob(self.basename + count_pattern + self.suffix) pictures = glob(self.basename + count_pattern + self.suffix)
@@ -48,21 +49,18 @@ class PictureList:
# Print initial infos # Print initial infos
logging.info('Number of last existing file: %d', self.counter) logging.info('Number of last existing file: %d', self.counter)
logging.info('Saving assembled pictures as "%s%s.%s"', self.basename, logging.info('Saving assembled pictures as "%s%s.%s"', self.basename,
self.count_width * 'X', 'jpg') self.count_width * 'X', 'jpg')
def getFilename(self, count): def getFilename(self, count):
"""Return the file name for a given file number"""
return self.basename + str(count).zfill(self.count_width) + self.suffix return self.basename + str(count).zfill(self.count_width) + self.suffix
def getLast(self): def getLast(self):
"""Return the current filename"""
return self.getFilename(self.counter) return self.getFilename(self.counter)
def getNext(self): def getNext(self):
"""Update counter and return the next filename"""
self.counter += 1 self.counter += 1
return self.getFilename(self.counter) return self.getFilename(self.counter)

View File

@@ -15,13 +15,11 @@ class WorkerTask:
assert not kwargs assert not kwargs
def get(self, picture): def get(self, picture):
raise NotImplementedError() raise NotImplementedError()
class PictureSaver(WorkerTask): class PictureSaver(WorkerTask):
def __init__(self, config): def __init__(self, config):
@@ -29,31 +27,27 @@ class PictureSaver(WorkerTask):
super().__init__() super().__init__()
path = os.path.join(config.get('Picture', 'basedir'), path = os.path.join(config.get('Picture', 'basedir'),
config.get('Picture', 'basename')) config.get('Picture', 'basename'))
basename = strftime(path, localtime()) basename = strftime(path, localtime())
self._pic_list = PictureList(basename) self._pic_list = PictureList(basename)
@staticmethod @staticmethod
def do(picture, filename): def do(picture, filename):
logging.info('Saving picture as %s', filename) logging.info('Saving picture as %s', filename)
picture.save(filename, 'JPEG') picture.save(filename, 'JPEG')
def get(self, picture): def get(self, picture):
return (self.do, (picture, self._pic_list.getNext())) return (self.do, (picture, self._pic_list.getNext()))
class Worker: class Worker:
def __init__(self, config, queue): def __init__(self, config, queue):
self._queue = queue self._queue = queue
def run(self): def run(self):
for func, args in iter(self._queue.get, 'teardown'): for func, args in iter(self._queue.get, 'teardown'):

View File

@@ -6,4 +6,3 @@ from .main import main
if __name__ == "__main__": if __name__ == "__main__":
sys.exit(main(sys.argv)) sys.exit(main(sys.argv))

View File

@@ -1,5 +1,7 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import sys, photobooth import sys
import photobooth
sys.exit(photobooth.main(sys.argv)) sys.exit(photobooth.main(sys.argv))

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import io, logging import io
import logging
from PIL import Image from PIL import Image
@@ -10,7 +11,6 @@ import gphoto2 as gp
from . import Camera from . import Camera
class CameraGphoto2(Camera): class CameraGphoto2(Camera):
def __init__(self): def __init__(self):
@@ -25,26 +25,24 @@ class CameraGphoto2(Camera):
self._setupLogging() self._setupLogging()
self._setupCamera() self._setupCamera()
def cleanup(self): def cleanup(self):
self._cap.set_config(self._oldconfig) self._cap.set_config(self._oldconfig)
self._cap.exit(self._ctxt) self._cap.exit(self._ctxt)
def _setupLogging(self): def _setupLogging(self):
gp.error_severity[gp.GP_ERROR] = logging.WARNING gp.error_severity[gp.GP_ERROR] = logging.WARNING
gp.check_result(gp.use_python_logging()) gp.check_result(gp.use_python_logging())
def _setupCamera(self): def _setupCamera(self):
self._ctxt = gp.Context() self._ctxt = gp.Context()
self._cap = gp.Camera() self._cap = gp.Camera()
self._cap.init(self._ctxt) self._cap.init(self._ctxt)
logging.info('Camera summary: %s', str(self._cap.get_summary(self._ctxt))) logging.info('Camera summary: %s',
str(self._cap.get_summary(self._ctxt)))
# get configuration tree # get configuration tree
# self._config = self._cap.get_config() # self._config = self._cap.get_config()
@@ -52,30 +50,30 @@ class CameraGphoto2(Camera):
config = self._cap.get_config() config = self._cap.get_config()
# make sure camera format is not set to raw # make sure camera format is not set to raw
if 'raw' in config.get_child_by_name('imageformat').get_value().lower(): imageformat = config.get_child_by_name('imageformat').get_value()
if 'raw' in imageformat.lower():
raise RuntimeError('Camera file format is set to RAW') raise RuntimeError('Camera file format is set to RAW')
self._printConfig(config) self._printConfig(config)
@staticmethod @staticmethod
def _configTreeToText(tree, indent=0): def _configTreeToText(tree, indent=0):
config_txt = '' config_txt = ''
for child in tree.get_children(): for chld in tree.get_children():
config_txt += indent * ' ' config_txt += indent * ' '
config_txt += child.get_label() + ' [' + child.get_name() + ']: ' config_txt += chld.get_label() + ' [' + chld.get_name() + ']: '
if child.count_children() > 0: if chld.count_children() > 0:
config_txt += '\n' config_txt += '\n'
config_txt += CameraGphoto2._configTreeToText(child, indent + 4) config_txt += CameraGphoto2._configTreeToText(chld, indent + 4)
else: else:
config_txt += str(child.get_value()) config_txt += str(chld.get_value())
try: try:
choice_txt = ' (' choice_txt = ' ('
for c in child.get_choices(): for c in chld.get_choices():
choice_txt += c + ', ' choice_txt += c + ', '
choice_txt += ')' choice_txt += ')'
@@ -86,43 +84,34 @@ class CameraGphoto2(Camera):
return config_txt return config_txt
@staticmethod @staticmethod
def _printConfig(config): def _printConfig(config):
config_txt = 'Camera configuration:\n' config_txt = 'Camera configuration:\n'
config_txt += CameraGphoto2._configTreeToText(config) config_txt += CameraGphoto2._configTreeToText(config)
logging.info(config_txt) logging.info(config_txt)
def setActive(self): def setActive(self):
config = self._cap.get_config() config = self._cap.get_config()
# self._config.get_child_by_name('viewfinder').set_value(True)
config.get_child_by_name('output').set_value('PC') config.get_child_by_name('output').set_value('PC')
self._cap.set_config(config) self._cap.set_config(config)
def setIdle(self): def setIdle(self):
config = self._cap.get_config() config = self._cap.get_config()
# self._config.get_child_by_name('viewfinder').set_value(False)
config.get_child_by_name('output').set_value('Off') config.get_child_by_name('output').set_value('Off')
self._cap.set_config(config) self._cap.set_config(config)
def getPreview(self): def getPreview(self):
# self._config.get_child_by_name('autofocusdrive').set_value(1)
# self._cap.set_config(self._config)
camera_file = self._cap.capture_preview() camera_file = self._cap.capture_preview()
file_data = camera_file.get_data_and_size() file_data = camera_file.get_data_and_size()
return Image.open(io.BytesIO(file_data)) return Image.open(io.BytesIO(file_data))
def getPicture(self): def getPicture(self):
file_path = self._cap.capture(gp.GP_CAPTURE_IMAGE) file_path = self._cap.capture(gp.GP_CAPTURE_IMAGE)
camera_file = self._cap.file_get(file_path.folder, file_path.name, gp.GP_FILE_TYPE_NORMAL) camera_file = self._cap.file_get(file_path.folder, file_path.name,
gp.GP_FILE_TYPE_NORMAL)
file_data = camera_file.get_data_and_size() file_data = camera_file.get_data_and_size()
return Image.open(io.BytesIO(file_data)) return Image.open(io.BytesIO(file_data))

View File

@@ -1,7 +1,8 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import io, logging import io
import logging
from PIL import Image from PIL import Image
@@ -23,18 +24,18 @@ class CameraGphoto2Cffi(Camera):
self._setupCamera() self._setupCamera()
def _setupCamera(self): def _setupCamera(self):
self._cap = gp.Camera() self._cap = gp.Camera()
logging.info('Supported operations: %s', self._cap.supported_operations) logging.info('Supported operations: %s',
self._cap.supported_operations)
if 'raw' in self._cap.config['imgsettings']['imageformat'].value.lower(): imageformat = self._cap.config['imgsettings']['imageformat'].value
if 'raw' in imageformat.lower():
raise RuntimeError('Camera file format is set to RAW') raise RuntimeError('Camera file format is set to RAW')
self._printConfig(self._cap.config) self._printConfig(self._cap.config)
@staticmethod @staticmethod
def _configTreeToText(config, indent=0): def _configTreeToText(config, indent=0):
@@ -46,38 +47,33 @@ class CameraGphoto2Cffi(Camera):
if hasattr(v, '__len__') and len(v) > 1: if hasattr(v, '__len__') and len(v) > 1:
config_txt += '\n' config_txt += '\n'
config_txt += CameraGphoto2Cffi._configTreeToText(v, indent + 4) config_txt += CameraGphoto2Cffi._configTreeToText(v,
indent + 4)
else: else:
config_txt += str(v) + '\n' config_txt += str(v) + '\n'
return config_txt return config_txt
@staticmethod @staticmethod
def _printConfig(config): def _printConfig(config):
config_txt = 'Camera configuration:\n' config_txt = 'Camera configuration:\n'
config_txt += CameraGphoto2Cffi._configTreeToText(config) config_txt += CameraGphoto2Cffi._configTreeToText(config)
logging.info(config_txt) logging.info(config_txt)
def setActive(self): def setActive(self):
self._cap._get_config()['actions']['viewfinder'].set(True) self._cap._get_config()['actions']['viewfinder'].set(True)
self._cap._get_config()['settings']['output'].set('PC') self._cap._get_config()['settings']['output'].set('PC')
def setIdle(self): def setIdle(self):
self._cap._get_config()['actions']['viewfinder'].set(False) self._cap._get_config()['actions']['viewfinder'].set(False)
self._cap._get_config()['settings']['output'].set('Off') self._cap._get_config()['settings']['output'].set('Off')
def getPreview(self): def getPreview(self):
return Image.open(io.BytesIO(self._cap.get_preview())) return Image.open(io.BytesIO(self._cap.get_preview()))
def getPicture(self): def getPicture(self):
return Image.open(io.BytesIO(self._cap.capture()))
return Image.open(io.BytesIO(self._cap.capture()))

View File

@@ -1,11 +1,15 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging
import os
import subprocess
from PIL import Image from PIL import Image
import os, subprocess, logging
from . import Camera from . import Camera
class CameraGphoto2CommandLine(Camera): class CameraGphoto2CommandLine(Camera):
def __init__(self): def __init__(self):
@@ -26,19 +30,17 @@ class CameraGphoto2CommandLine(Camera):
self.setActive() self.setActive()
def setActive(self): def setActive(self):
print(self._callGphoto('-a', '/dev/null')) self._callGphoto('-a', '/dev/null')
def getPicture(self): def getPicture(self):
self._callGphoto('--capture-image-and-download', self._tmp_filename) self._callGphoto('--capture-image-and-download', self._tmp_filename)
return Image.open(self._tmp_filename) return Image.open(self._tmp_filename)
def _callGphoto(self, action, filename): def _callGphoto(self, action, filename):
cmd = 'gphoto2 --force-overwrite --quiet ' + action + ' --filename ' + filename cmd = 'gphoto2 --force-overwrite --quiet {} --filename {}'
return subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT) return subprocess.check_output(cmd.format(action, filename),
shell=True, stderr=subprocess.STDOUT)

View File

@@ -9,6 +9,7 @@ import cv2
from . import Camera from . import Camera
class CameraOpenCV(Camera): class CameraOpenCV(Camera):
def __init__(self): def __init__(self):
@@ -22,7 +23,6 @@ class CameraOpenCV(Camera):
self._cap = cv2.VideoCapture() self._cap = cv2.VideoCapture()
def setActive(self): def setActive(self):
if not self._cap.isOpened(): if not self._cap.isOpened():
@@ -30,20 +30,17 @@ class CameraOpenCV(Camera):
if not self._cap.isOpened(): if not self._cap.isOpened():
raise RuntimeError('Camera could not be opened') raise RuntimeError('Camera could not be opened')
def setIdle(self): def setIdle(self):
if self._cap.isOpened(): if self._cap.isOpened():
self._cap.release() self._cap.release()
def getPreview(self): def getPreview(self):
return self.getPicture() return self.getPicture()
def getPicture(self): def getPicture(self):
self.setActive() self.setActive()
status, frame = self._cap.read() status, frame = self._cap.read()
if not status: if not status:
@@ -52,4 +49,3 @@ class CameraOpenCV(Camera):
# OpenCV yields frames in BGR format, conversion to RGB necessary. # OpenCV yields frames in BGR format, conversion to RGB necessary.
# (See https://stackoverflow.com/a/32270308) # (See https://stackoverflow.com/a/32270308)
return Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)) return Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))

View File

@@ -6,8 +6,9 @@
modules = ( modules = (
('python-gphoto2', 'CameraGphoto2', 'CameraGphoto2'), ('python-gphoto2', 'CameraGphoto2', 'CameraGphoto2'),
('gphoto2-cffi', 'CameraGphoto2Cffi', 'CameraGphoto2Cffi'), ('gphoto2-cffi', 'CameraGphoto2Cffi', 'CameraGphoto2Cffi'),
('gphoto2-commandline', 'CameraGphoto2CommandLine', 'CameraGphoto2CommandLine'), ('gphoto2-commandline', 'CameraGphoto2CommandLine',
('opencv', 'CameraOpenCV', 'CameraOpenCV') ) 'CameraGphoto2CommandLine'),
('opencv', 'CameraOpenCV', 'CameraOpenCV'))
class Camera: class Camera:
@@ -17,28 +18,23 @@ class Camera:
self.hasPreview = False self.hasPreview = False
self.hasIdle = False self.hasIdle = False
def __enter__(self): def __enter__(self):
return self return self
def __exit__(self, exc_type, exc_value, traceback): def __exit__(self, exc_type, exc_value, traceback):
self.cleanup() self.cleanup()
def cleanup(self): def cleanup(self):
pass pass
@property @property
def hasPreview(self): def hasPreview(self):
return self._has_preview return self._has_preview
@hasPreview.setter @hasPreview.setter
def hasPreview(self, value): def hasPreview(self, value):
@@ -51,7 +47,6 @@ class Camera:
def hasIdle(self): def hasIdle(self):
return self._has_idle return self._has_idle
@hasIdle.setter @hasIdle.setter
def hasIdle(self, value): def hasIdle(self, value):
@@ -61,7 +56,6 @@ class Camera:
self._has_idle = value self._has_idle = value
def setActive(self): def setActive(self):
if not self.hasIdle: if not self.hasIdle:
@@ -69,7 +63,6 @@ class Camera:
else: else:
raise NotImplementedError() raise NotImplementedError()
def setIdle(self): def setIdle(self):
if not self.hasIdle: if not self.hasIdle:
@@ -77,7 +70,6 @@ class Camera:
raise NotImplementedError() raise NotImplementedError()
def getPreview(self): def getPreview(self):
if not self.hasPreview: if not self.hasPreview:
@@ -85,15 +77,6 @@ class Camera:
raise NotImplementedError() raise NotImplementedError()
def getPicture(self): def getPicture(self):
raise NotImplementedError() raise NotImplementedError()
def setIdle(self):
if not self.hasIdle:
raise RuntimeError('Camera does not support idle state')
raise NotImplementedError()

View File

@@ -3,31 +3,26 @@
import logging import logging
from PyQt5.QtWidgets import QMessageBox
from .. import printer from .. import printer
from ..util import lookup_and_import from ..util import lookup_and_import
from .GuiState import PrintState from .GuiState import PrintState
class GuiPostprocess: class GuiPostprocess:
def __init__(self, **kwargs): def __init__(self, **kwargs):
assert not kwargs assert not kwargs
def get(self, picture): def get(self, picture):
raise NotImplementedError() raise NotImplementedError()
def confirm(self, picture): def confirm(self, picture):
raise NotImplementedError() raise NotImplementedError()
class PrintPostprocess(GuiPostprocess): class PrintPostprocess(GuiPostprocess):
def __init__(self, printer_module, page_size, **kwargs): def __init__(self, printer_module, page_size, **kwargs):
@@ -37,16 +32,13 @@ class PrintPostprocess(GuiPostprocess):
Printer = lookup_and_import(printer.modules, printer_module, 'printer') Printer = lookup_and_import(printer.modules, printer_module, 'printer')
self._printer = Printer(page_size) self._printer = Printer(page_size)
def get(self, picture): def get(self, picture):
return PrintState(lambda : self.do(picture), False) return PrintState(lambda: self.do(picture), False)
def confirm(self, picture): def confirm(self, picture):
return PrintState(lambda : None, True) return PrintState(lambda: None, True)
def do(self, picture): def do(self, picture):

View File

@@ -9,7 +9,6 @@ class GuiState:
assert not kwargs assert not kwargs
class ErrorState(GuiState): class ErrorState(GuiState):
def __init__(self, title, message, **kwargs): def __init__(self, title, message, **kwargs):
@@ -18,26 +17,22 @@ class ErrorState(GuiState):
self.title = title self.title = title
self.message = message self.message = message
@property @property
def title(self): def title(self):
return self._title return self._title
@title.setter @title.setter
def title(self, title): def title(self, title):
self._title = title self._title = title
@property @property
def message(self): def message(self):
return self._message return self._message
@message.setter @message.setter
def message(self, message): def message(self, message):
@@ -59,13 +54,11 @@ class PictureState(GuiState):
self.picture = picture self.picture = picture
@property @property
def picture(self): def picture(self):
return self._pic return self._pic
@picture.setter @picture.setter
def picture(self, picture): def picture(self, picture):
@@ -80,13 +73,11 @@ class MessageState(GuiState):
self.message = message self.message = message
@property @property
def message(self): def message(self):
return self._msg return self._msg
@message.setter @message.setter
def message(self, message): def message(self, message):
@@ -154,13 +145,11 @@ class PrintState(GuiState):
self.handler = handler self.handler = handler
self.confirmed = confirmed self.confirmed = confirmed
@property @property
def handler(self): def handler(self):
return self._handler return self._handler
@handler.setter @handler.setter
def handler(self, handler): def handler(self, handler):
@@ -169,7 +158,6 @@ class PrintState(GuiState):
self._handler = handler self._handler = handler
@property @property
def confirmed(self): def confirmed(self):
@@ -182,4 +170,3 @@ class PrintState(GuiState):
raise ValueError('confirmed status must be bool') raise ValueError('confirmed status must be bool')
self._confirmed = confirmed self._confirmed = confirmed

View File

@@ -8,21 +8,15 @@ from os.path import expanduser
from PIL import ImageQt from PIL import ImageQt
from PyQt5.QtCore import Qt, QObject, QPoint, QThread, QTimer, pyqtSignal from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtWidgets import (QFileDialog, QTabWidget, QApplication, QCheckBox, QComboBox, QFormLayout, QFrame, QGridLayout, QGroupBox, QHBoxLayout, QLabel, QLayout, QLineEdit, QMainWindow, QMessageBox, QPushButton, QVBoxLayout, QWidget)
from PyQt5.QtGui import QImage, QPainter, QPixmap
import math import math
from PyQt5.QtGui import QBrush, QPen, QColor, QFont
from PyQt5.QtCore import QRect
from .PyQt5GuiHelpers import QRoundProgressBar from .PyQt5GuiHelpers import QRoundProgressBar
from . import * from . import *
from .. import camera, printer from .. import camera, printer
from ..printer.PrinterPyQt5 import PrinterPyQt5 as Printer
class PyQt5Gui(Gui): class PyQt5Gui(Gui):
@@ -33,7 +27,7 @@ class PyQt5Gui(Gui):
global cfg global cfg
cfg = config cfg = config
self._app = QApplication(argv) self._app = QtWidgets.QApplication(argv)
self._p = PyQt5MainWindow() self._p = PyQt5MainWindow()
self._lastState = self.showStart self._lastState = self.showStart
@@ -94,15 +88,15 @@ class PyQt5Gui(Gui):
def handleKeypressEvent(self, event): def handleKeypressEvent(self, event):
if event.key() == Qt.Key_Escape: if event.key() == QtCore.Qt.Key_Escape:
self.handleState(TeardownState()) self.handleState(TeardownState())
elif event.key() == Qt.Key_Space: elif event.key() == QtCore.Qt.Key_Space:
self.handleState(TriggerState()) self.handleState(TriggerState())
def handleKeypressEventNoTrigger(self, event): def handleKeypressEventNoTrigger(self, event):
if event.key() == Qt.Key_Escape: if event.key() == QtCore.Qt.Key_Escape:
self.handleState(TeardownState()) self.handleState(TeardownState())
@@ -122,7 +116,7 @@ class PyQt5Gui(Gui):
self._p.handleKeypressEvent = self.handleKeypressEventNoTrigger self._p.handleKeypressEvent = self.handleKeypressEventNoTrigger
self._p.setCentralWidget( PyQt5GreeterMessage( self._p.setCentralWidget( PyQt5GreeterMessage(
cfg.getInt('Picture', 'num_x'), cfg.getInt('Picture', 'num_y') ) ) cfg.getInt('Picture', 'num_x'), cfg.getInt('Picture', 'num_y') ) )
QTimer.singleShot(cfg.getInt('Photobooth', 'greeter_time') * 1000, self.sendAck) QtCore.QTimer.singleShot(cfg.getInt('Photobooth', 'greeter_time') * 1000, self.sendAck)
elif isinstance(state, CountdownState): elif isinstance(state, CountdownState):
self._p.setCentralWidget(PyQt5CountdownMessage(cfg.getInt('Photobooth', 'countdown_time'), self.sendAck)) self._p.setCentralWidget(PyQt5CountdownMessage(cfg.getInt('Photobooth', 'countdown_time'), self.sendAck))
@@ -140,7 +134,7 @@ 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, QtCore.QTimer.singleShot(cfg.getInt('Photobooth', 'display_time') * 1000,
lambda : self.postprocessPicture(state.picture)) lambda : self.postprocessPicture(state.picture))
elif isinstance(state, TeardownState): elif isinstance(state, TeardownState):
@@ -172,13 +166,13 @@ class PyQt5Gui(Gui):
break break
else: else:
if isinstance(task, PrintState): if isinstance(task, PrintState):
reply = QMessageBox.question(self._p, 'Print picture?', reply = QtWidgets.QMessageBox.question(self._p, 'Print picture?',
'Do you want to print the picture?', 'Do you want to print the picture?',
QMessageBox.Yes | QMessageBox.No, QMessageBox.No) QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
if reply == QMessageBox.Yes: if reply == QtWidgets.QMessageBox.Yes:
task.handler() task.handler()
QMessageBox.information(self._p, 'Printing', QtWidgets.QMessageBox.information(self._p, 'Printing',
'Picture sent to printer.', QMessageBox.Ok) 'Picture sent to printer.', QtWidgets.QMessageBox.Ok)
else: else:
raise ValueError('Unknown task') raise ValueError('Unknown task')
@@ -188,8 +182,8 @@ class PyQt5Gui(Gui):
self._p.handleKeypressEvent = lambda event : None self._p.handleKeypressEvent = lambda event : None
self._lastState = self.showStart self._lastState = self.showStart
self._p.setCentralWidget(PyQt5Start(self)) self._p.setCentralWidget(PyQt5Start(self))
if QApplication.overrideCursor() != 0: if QtWidgets.QApplication.overrideCursor() != 0:
QApplication.restoreOverrideCursor() QtWidgets.QApplication.restoreOverrideCursor()
def showSettings(self): def showSettings(self):
@@ -205,7 +199,7 @@ class PyQt5Gui(Gui):
self._conn.send('start') self._conn.send('start')
self._p.setCentralWidget(PyQt5WaitMessage('Starting the photobooth...')) self._p.setCentralWidget(PyQt5WaitMessage('Starting the photobooth...'))
if cfg.getBool('Gui', 'hide_cursor'): if cfg.getBool('Gui', 'hide_cursor'):
QApplication.setOverrideCursor(Qt.BlankCursor) QtWidgets.QApplication.setOverrideCursor(QtCore.Qt.BlankCursor)
def showIdle(self): def showIdle(self):
@@ -218,9 +212,9 @@ class PyQt5Gui(Gui):
def showError(self, title, message): def showError(self, title, message):
logging.error('%s: %s', title, message) logging.error('%s: %s', title, message)
reply = QMessageBox.warning(self._p, title, message, reply = QtWidgets.QMessageBox.warning(self._p, title, message,
QMessageBox.Close | QMessageBox.Retry, QMessageBox.Retry) QtWidgets.QMessageBox.Close | QtWidgets.QMessageBox.Retry, QtWidgets.QMessageBox.Retry)
if reply == QMessageBox.Retry: if reply == QtWidgets.QMessageBox.Retry:
self.sendAck() self.sendAck()
self._lastState() self._lastState()
else: else:
@@ -228,9 +222,9 @@ class PyQt5Gui(Gui):
self.showStart() self.showStart()
class PyQt5Receiver(QThread): class PyQt5Receiver(QtCore.QThread):
notify = pyqtSignal(object) notify = QtCore.pyqtSignal(object)
def __init__(self, conn): def __init__(self, conn):
@@ -257,7 +251,7 @@ class PyQt5Receiver(QThread):
class PyQt5MainWindow(QMainWindow): class PyQt5MainWindow(QtWidgets.QMainWindow):
def __init__(self): def __init__(self):
@@ -299,10 +293,10 @@ class PyQt5MainWindow(QMainWindow):
def closeEvent(self, e): def closeEvent(self, e):
reply = QMessageBox.question(self, 'Confirmation', "Quit Photobooth?", reply = QtWidgets.QMessageBox.question(self, 'Confirmation', "Quit Photobooth?",
QMessageBox.Yes | QMessageBox.No, QMessageBox.No) QtWidgets.QMessageBox.Yes | QtWidgets.QMessageBox.No, QtWidgets.QMessageBox.No)
if reply == QMessageBox.Yes: if reply == QtWidgets.QMessageBox.Yes:
e.accept() e.accept()
else: else:
e.ignore() e.ignore()
@@ -315,7 +309,7 @@ class PyQt5MainWindow(QMainWindow):
class PyQt5Start(QFrame): class PyQt5Start(QtWidgets.QFrame):
def __init__(self, gui): def __init__(self, gui):
@@ -326,28 +320,28 @@ class PyQt5Start(QFrame):
def initFrame(self, gui): def initFrame(self, gui):
grid = QGridLayout() grid = QtWidgets.QGridLayout()
grid.setSpacing(100) grid.setSpacing(100)
self.setLayout(grid) self.setLayout(grid)
btnStart = QPushButton('Start Photobooth') btnStart = QtWidgets.QPushButton('Start Photobooth')
btnStart.resize(btnStart.sizeHint()) btnStart.resize(btnStart.sizeHint())
btnStart.clicked.connect(gui.showStartPhotobooth) btnStart.clicked.connect(gui.showStartPhotobooth)
grid.addWidget(btnStart, 0, 0) grid.addWidget(btnStart, 0, 0)
btnSettings = QPushButton('Settings') btnSettings = QtWidgets.QPushButton('Settings')
btnSettings.resize(btnSettings.sizeHint()) btnSettings.resize(btnSettings.sizeHint())
btnSettings.clicked.connect(gui.showSettings) btnSettings.clicked.connect(gui.showSettings)
grid.addWidget(btnSettings, 0, 1) grid.addWidget(btnSettings, 0, 1)
btnQuit = QPushButton('Quit') btnQuit = QtWidgets.QPushButton('Quit')
btnQuit.resize(btnQuit.sizeHint()) btnQuit.resize(btnQuit.sizeHint())
btnQuit.clicked.connect(gui.close) btnQuit.clicked.connect(gui.close)
grid.addWidget(btnQuit, 0, 2) grid.addWidget(btnQuit, 0, 2)
class PyQt5Settings(QFrame): class PyQt5Settings(QtWidgets.QFrame):
def __init__(self, gui): def __init__(self, gui):
@@ -362,7 +356,7 @@ class PyQt5Settings(QFrame):
self._value_widgets = {} self._value_widgets = {}
layout = QVBoxLayout() layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.createTabs()) layout.addWidget(self.createTabs())
layout.addStretch(1) layout.addStretch(1)
layout.addWidget(self.createButtons()) layout.addWidget(self.createButtons())
@@ -371,7 +365,7 @@ class PyQt5Settings(QFrame):
def createTabs(self): def createTabs(self):
tabs = QTabWidget() tabs = QtWidgets.QTabWidget()
tabs.addTab(self.createGuiSettings(), 'Interface') tabs.addTab(self.createGuiSettings(), 'Interface')
tabs.addTab(self.createPhotoboothSettings(), 'Photobooth') tabs.addTab(self.createPhotoboothSettings(), 'Photobooth')
tabs.addTab(self.createCameraSettings(), 'Camera') tabs.addTab(self.createCameraSettings(), 'Camera')
@@ -384,32 +378,32 @@ class PyQt5Settings(QFrame):
def createButtons(self): def createButtons(self):
layout = QHBoxLayout() layout = QtWidgets.QHBoxLayout()
layout.addStretch(1) layout.addStretch(1)
btnSave = QPushButton('Save and restart') btnSave = QtWidgets.QPushButton('Save and restart')
btnSave.resize(btnSave.sizeHint()) btnSave.resize(btnSave.sizeHint())
btnSave.clicked.connect(self.storeConfigAndRestart) btnSave.clicked.connect(self.storeConfigAndRestart)
layout.addWidget(btnSave) layout.addWidget(btnSave)
btnCancel = QPushButton('Cancel') btnCancel = QtWidgets.QPushButton('Cancel')
btnCancel.resize(btnCancel.sizeHint()) btnCancel.resize(btnCancel.sizeHint())
btnCancel.clicked.connect(self._gui.showStart) btnCancel.clicked.connect(self._gui.showStart)
layout.addWidget(btnCancel) layout.addWidget(btnCancel)
btnRestore = QPushButton('Restore defaults') btnRestore = QtWidgets.QPushButton('Restore defaults')
btnRestore.resize(btnRestore.sizeHint()) btnRestore.resize(btnRestore.sizeHint())
btnRestore.clicked.connect(self.restoreDefaults) btnRestore.clicked.connect(self.restoreDefaults)
layout.addWidget(btnRestore) layout.addWidget(btnRestore)
widget = QGroupBox() widget = QtWidgets.QGroupBox()
widget.setLayout(layout) widget.setLayout(layout)
return widget return widget
def createModuleComboBox(self, module_list, current_module): def createModuleComboBox(self, module_list, current_module):
cb = QComboBox() cb = QtWidgets.QComboBox()
for m in module_list: for m in module_list:
cb.addItem(m[0]) cb.addItem(m[0])
@@ -424,30 +418,30 @@ class PyQt5Settings(QFrame):
global cfg global cfg
self._value_widgets['Gui'] = {} self._value_widgets['Gui'] = {}
self._value_widgets['Gui']['fullscreen'] = QCheckBox('Enable fullscreen') self._value_widgets['Gui']['fullscreen'] = QtWidgets.QCheckBox('Enable fullscreen')
if cfg.getBool('Gui', 'fullscreen'): if cfg.getBool('Gui', 'fullscreen'):
self._value_widgets['Gui']['fullscreen'].toggle() self._value_widgets['Gui']['fullscreen'].toggle()
self._value_widgets['Gui']['module'] = self.createModuleComboBox(modules, cfg.get('Gui', 'module')) self._value_widgets['Gui']['module'] = self.createModuleComboBox(modules, cfg.get('Gui', 'module'))
self._value_widgets['Gui']['width'] = QLineEdit(cfg.get('Gui', 'width')) self._value_widgets['Gui']['width'] = QtWidgets.QLineEdit(cfg.get('Gui', 'width'))
self._value_widgets['Gui']['height'] = QLineEdit(cfg.get('Gui', 'height')) self._value_widgets['Gui']['height'] = QtWidgets.QLineEdit(cfg.get('Gui', 'height'))
self._value_widgets['Gui']['hide_cursor'] = QCheckBox('Hide cursor') self._value_widgets['Gui']['hide_cursor'] = QtWidgets.QCheckBox('Hide cursor')
if cfg.getBool('Gui', 'hide_cursor'): if cfg.getBool('Gui', 'hide_cursor'):
self._value_widgets['Gui']['hide_cursor'].toggle() self._value_widgets['Gui']['hide_cursor'].toggle()
layout = QFormLayout() layout = QtWidgets.QFormLayout()
layout.addRow(self._value_widgets['Gui']['fullscreen']) layout.addRow(self._value_widgets['Gui']['fullscreen'])
layout.addRow(QLabel('Gui module:'), self._value_widgets['Gui']['module']) layout.addRow(QtWidgets.QLabel('Gui module:'), self._value_widgets['Gui']['module'])
sublayout_size = QHBoxLayout() sublayout_size = QtWidgets.QHBoxLayout()
sublayout_size.addWidget(QLabel('Window size [px]:')) sublayout_size.addWidget(QtWidgets.QLabel('Window size [px]:'))
sublayout_size.addWidget(self._value_widgets['Gui']['width']) sublayout_size.addWidget(self._value_widgets['Gui']['width'])
sublayout_size.addWidget(QLabel('x')) sublayout_size.addWidget(QtWidgets.QLabel('x'))
sublayout_size.addWidget(self._value_widgets['Gui']['height']) sublayout_size.addWidget(self._value_widgets['Gui']['height'])
layout.addRow(sublayout_size) layout.addRow(sublayout_size)
layout.addRow(self._value_widgets['Gui']['hide_cursor']) layout.addRow(self._value_widgets['Gui']['hide_cursor'])
widget = QWidget() widget = QtWidgets.QWidget()
widget.setLayout(layout) widget.setLayout(layout)
return widget return widget
@@ -457,21 +451,20 @@ class PyQt5Settings(QFrame):
global cfg global cfg
self._value_widgets['Gpio'] = {} self._value_widgets['Gpio'] = {}
self._value_widgets['Gpio']['enable'] = QCheckBox('Enable GPIO') self._value_widgets['Gpio']['enable'] = QtWidgets.QCheckBox('Enable GPIO')
if cfg.getBool('Gpio', 'enable'): if cfg.getBool('Gpio', 'enable'):
self._value_widgets['Gpio']['enable'].toggle() self._value_widgets['Gpio']['enable'].toggle()
self._value_widgets['Gpio']['exit_pin'] = QLineEdit(cfg.get('Gpio', 'exit_pin')) self._value_widgets['Gpio']['exit_pin'] = QtWidgets.QLineEdit(cfg.get('Gpio', 'exit_pin'))
self._value_widgets['Gpio']['trigger_pin'] = QLineEdit(cfg.get('Gpio', 'trigger_pin')) self._value_widgets['Gpio']['trigger_pin'] = QtWidgets.QLineEdit(cfg.get('Gpio', 'trigger_pin'))
self._value_widgets['Gpio']['lamp_pin'] = QLineEdit(cfg.get('Gpio', 'lamp_pin')) self._value_widgets['Gpio']['lamp_pin'] = QtWidgets.QLineEdit(cfg.get('Gpio', 'lamp_pin'))
layout = QFormLayout() layout = QtWidgets.QFormLayout()
layout.addRow(self._value_widgets['Gpio']['enable']) layout.addRow(self._value_widgets['Gpio']['enable'])
layout.addRow(QLabel('Exit pin (BCM numbering):'), self._value_widgets['Gpio']['exit_pin']) layout.addRow(QtWidgets.QLabel('Exit pin (BCM numbering):'), self._value_widgets['Gpio']['exit_pin'])
layout.addRow(QLabel('Trigger pin (BCM numbering):'), self._value_widgets['Gpio']['trigger_pin']) layout.addRow(QtWidgets.QLabel('Trigger pin (BCM numbering):'), self._value_widgets['Gpio']['trigger_pin'])
layout.addRow(QLabel('Lamp pin (BCM numbering):'), self._value_widgets['Gpio']['lamp_pin']) layout.addRow(QtWidgets.QLabel('Lamp pin (BCM numbering):'), self._value_widgets['Gpio']['lamp_pin'])
# widget = QGroupBox('GPIO settings') widget = QtWidgets.QWidget()
widget = QWidget()
widget.setLayout(layout) widget.setLayout(layout)
return widget return widget
@@ -481,26 +474,25 @@ class PyQt5Settings(QFrame):
global cfg global cfg
self._value_widgets['Printer'] = {} self._value_widgets['Printer'] = {}
self._value_widgets['Printer']['enable'] = QCheckBox('Enable Printing') self._value_widgets['Printer']['enable'] = QtWidgets.QCheckBox('Enable Printing')
if cfg.getBool('Printer', 'enable'): if cfg.getBool('Printer', 'enable'):
self._value_widgets['Printer']['enable'].toggle() self._value_widgets['Printer']['enable'].toggle()
self._value_widgets['Printer']['module'] = self.createModuleComboBox(printer.modules, cfg.get('Printer', 'module')) self._value_widgets['Printer']['module'] = self.createModuleComboBox(printer.modules, cfg.get('Printer', 'module'))
self._value_widgets['Printer']['width'] = QLineEdit(cfg.get('Printer', 'width')) self._value_widgets['Printer']['width'] = QtWidgets.QLineEdit(cfg.get('Printer', 'width'))
self._value_widgets['Printer']['height'] = QLineEdit(cfg.get('Printer', 'height')) self._value_widgets['Printer']['height'] = QtWidgets.QLineEdit(cfg.get('Printer', 'height'))
layout = QFormLayout() layout = QtWidgets.QFormLayout()
layout.addRow(self._value_widgets['Printer']['enable']) layout.addRow(self._value_widgets['Printer']['enable'])
layout.addRow(QLabel('Printer module:'), self._value_widgets['Printer']['module']) layout.addRow(QtWidgets.QLabel('Printer module:'), self._value_widgets['Printer']['module'])
sublayout_size = QHBoxLayout() sublayout_size = QtWidgets.QHBoxLayout()
sublayout_size.addWidget(QLabel('Paper size [mm]:')) sublayout_size.addWidget(QtWidgets.QLabel('Paper size [mm]:'))
sublayout_size.addWidget(self._value_widgets['Printer']['width']) sublayout_size.addWidget(self._value_widgets['Printer']['width'])
sublayout_size.addWidget(QLabel('x')) sublayout_size.addWidget(QtWidgets.QLabel('x'))
sublayout_size.addWidget(self._value_widgets['Printer']['height']) sublayout_size.addWidget(self._value_widgets['Printer']['height'])
layout.addRow(sublayout_size) layout.addRow(sublayout_size)
# widget = QGroupBox('Printer settings') widget = QtWidgets.QWidget()
widget = QWidget()
widget.setLayout(layout) widget.setLayout(layout)
return widget return widget
@@ -512,11 +504,10 @@ class PyQt5Settings(QFrame):
self._value_widgets['Camera'] = {} self._value_widgets['Camera'] = {}
self._value_widgets['Camera']['module'] = self.createModuleComboBox(camera.modules, cfg.get('Camera', 'module')) self._value_widgets['Camera']['module'] = self.createModuleComboBox(camera.modules, cfg.get('Camera', 'module'))
layout = QFormLayout() layout = QtWidgets.QFormLayout()
layout.addRow(QLabel('Camera module:'), self._value_widgets['Camera']['module']) layout.addRow(QtWidgets.QLabel('Camera module:'), self._value_widgets['Camera']['module'])
# widget = QGroupBox('Camera settings') widget = QtWidgets.QWidget()
widget = QWidget()
widget.setLayout(layout) widget.setLayout(layout)
return widget return widget
@@ -526,21 +517,20 @@ class PyQt5Settings(QFrame):
global cfg global cfg
self._value_widgets['Photobooth'] = {} self._value_widgets['Photobooth'] = {}
self._value_widgets['Photobooth']['show_preview'] = QCheckBox('Show preview while countdown') self._value_widgets['Photobooth']['show_preview'] = QtWidgets.QCheckBox('Show preview while countdown')
if cfg.getBool('Photobooth', 'show_preview'): if cfg.getBool('Photobooth', 'show_preview'):
self._value_widgets['Photobooth']['show_preview'].toggle() self._value_widgets['Photobooth']['show_preview'].toggle()
self._value_widgets['Photobooth']['greeter_time'] = QLineEdit(cfg.get('Photobooth', 'greeter_time')) self._value_widgets['Photobooth']['greeter_time'] = QtWidgets.QLineEdit(cfg.get('Photobooth', 'greeter_time'))
self._value_widgets['Photobooth']['countdown_time'] = QLineEdit(cfg.get('Photobooth', 'countdown_time')) self._value_widgets['Photobooth']['countdown_time'] = QtWidgets.QLineEdit(cfg.get('Photobooth', 'countdown_time'))
self._value_widgets['Photobooth']['display_time'] = QLineEdit(cfg.get('Photobooth', 'display_time')) self._value_widgets['Photobooth']['display_time'] = QtWidgets.QLineEdit(cfg.get('Photobooth', 'display_time'))
layout = QFormLayout() layout = QtWidgets.QFormLayout()
layout.addRow(self._value_widgets['Photobooth']['show_preview']) layout.addRow(self._value_widgets['Photobooth']['show_preview'])
layout.addRow(QLabel('Greeter time [s]:'), self._value_widgets['Photobooth']['greeter_time']) layout.addRow(QtWidgets.QLabel('Greeter time [s]:'), self._value_widgets['Photobooth']['greeter_time'])
layout.addRow(QLabel('Countdown time [s]:'), self._value_widgets['Photobooth']['countdown_time']) layout.addRow(QtWidgets.QLabel('Countdown time [s]:'), self._value_widgets['Photobooth']['countdown_time'])
layout.addRow(QLabel('Display time [s]:'), self._value_widgets['Photobooth']['display_time']) layout.addRow(QtWidgets.QLabel('Display time [s]:'), self._value_widgets['Photobooth']['display_time'])
# widget = QGroupBox('Photobooth settings') widget = QtWidgets.QWidget()
widget = QWidget()
widget.setLayout(layout) widget.setLayout(layout)
return widget return widget
@@ -550,54 +540,54 @@ class PyQt5Settings(QFrame):
global cfg global cfg
self._value_widgets['Picture'] = {} self._value_widgets['Picture'] = {}
self._value_widgets['Picture']['num_x'] = QLineEdit(cfg.get('Picture', 'num_x')) self._value_widgets['Picture']['num_x'] = QtWidgets.QLineEdit(cfg.get('Picture', 'num_x'))
self._value_widgets['Picture']['num_y'] = QLineEdit(cfg.get('Picture', 'num_y')) self._value_widgets['Picture']['num_y'] = QtWidgets.QLineEdit(cfg.get('Picture', 'num_y'))
self._value_widgets['Picture']['size_x'] = QLineEdit(cfg.get('Picture', 'size_x')) self._value_widgets['Picture']['size_x'] = QtWidgets.QLineEdit(cfg.get('Picture', 'size_x'))
self._value_widgets['Picture']['size_y'] = QLineEdit(cfg.get('Picture', 'size_y')) self._value_widgets['Picture']['size_y'] = QtWidgets.QLineEdit(cfg.get('Picture', 'size_y'))
self._value_widgets['Picture']['min_dist_x'] = QLineEdit(cfg.get('Picture', 'min_dist_x')) self._value_widgets['Picture']['min_dist_x'] = QtWidgets.QLineEdit(cfg.get('Picture', 'min_dist_x'))
self._value_widgets['Picture']['min_dist_y'] = QLineEdit(cfg.get('Picture', 'min_dist_y')) self._value_widgets['Picture']['min_dist_y'] = QtWidgets.QLineEdit(cfg.get('Picture', 'min_dist_y'))
self._value_widgets['Picture']['basedir'] = QLineEdit(cfg.get('Picture', 'basedir')) self._value_widgets['Picture']['basedir'] = QtWidgets.QLineEdit(cfg.get('Picture', 'basedir'))
self._value_widgets['Picture']['basename'] = QLineEdit(cfg.get('Picture', 'basename')) self._value_widgets['Picture']['basename'] = QtWidgets.QLineEdit(cfg.get('Picture', 'basename'))
layout = QFormLayout() layout = QtWidgets.QFormLayout()
sublayout_num = QHBoxLayout() sublayout_num = QtWidgets.QHBoxLayout()
sublayout_num.addWidget(QLabel('Number of shots per picture:')) sublayout_num.addWidget(QtWidgets.QLabel('Number of shots per picture:'))
sublayout_num.addWidget(self._value_widgets['Picture']['num_x']) sublayout_num.addWidget(self._value_widgets['Picture']['num_x'])
sublayout_num.addWidget(QLabel('x')) sublayout_num.addWidget(QtWidgets.QLabel('x'))
sublayout_num.addWidget(self._value_widgets['Picture']['num_y']) sublayout_num.addWidget(self._value_widgets['Picture']['num_y'])
layout.addRow(sublayout_num) layout.addRow(sublayout_num)
sublayout_size = QHBoxLayout() sublayout_size = QtWidgets.QHBoxLayout()
sublayout_size.addWidget(QLabel('Size of assembled picture:')) sublayout_size.addWidget(QtWidgets.QLabel('Size of assembled picture:'))
sublayout_size.addWidget(self._value_widgets['Picture']['size_x']) sublayout_size.addWidget(self._value_widgets['Picture']['size_x'])
sublayout_size.addWidget(QLabel('x')) sublayout_size.addWidget(QtWidgets.QLabel('x'))
sublayout_size.addWidget(self._value_widgets['Picture']['size_y']) sublayout_size.addWidget(self._value_widgets['Picture']['size_y'])
layout.addRow(sublayout_size) layout.addRow(sublayout_size)
sublayout_dist = QHBoxLayout() sublayout_dist = QtWidgets.QHBoxLayout()
sublayout_dist.addWidget(QLabel('Min. distance between shots in picture:')) sublayout_dist.addWidget(QtWidgets.QLabel('Min. distance between shots in picture:'))
sublayout_dist.addWidget(self._value_widgets['Picture']['min_dist_x']) sublayout_dist.addWidget(self._value_widgets['Picture']['min_dist_x'])
sublayout_dist.addWidget(QLabel('x')) sublayout_dist.addWidget(QtWidgets.QLabel('x'))
sublayout_dist.addWidget(self._value_widgets['Picture']['min_dist_y']) sublayout_dist.addWidget(self._value_widgets['Picture']['min_dist_y'])
layout.addRow(sublayout_dist) layout.addRow(sublayout_dist)
file_dialog = lambda : self._value_widgets['Picture']['basedir'].setText( file_dialog = lambda : self._value_widgets['Picture']['basedir'].setText(
QFileDialog.getExistingDirectory(self, 'Select directory', QtWidgets.QFileDialog.getExistingDirectory(self, 'Select directory',
expanduser('~'), QFileDialog.ShowDirsOnly)) expanduser('~'), QtWidgets.QFileDialog.ShowDirsOnly))
file_button = QPushButton('Select directory') file_button = QtWidgets.QPushButton('Select directory')
file_button.resize(file_button.sizeHint()) file_button.resize(file_button.sizeHint())
file_button.clicked.connect(file_dialog) file_button.clicked.connect(file_dialog)
sublayout_path = QHBoxLayout() sublayout_path = QtWidgets.QHBoxLayout()
sublayout_path.addWidget(QLabel('Basename of output files:')) sublayout_path.addWidget(QtWidgets.QLabel('Basename of output files:'))
sublayout_path.addWidget(self._value_widgets['Picture']['basedir']) sublayout_path.addWidget(self._value_widgets['Picture']['basedir'])
sublayout_path.addWidget(QLabel('/')) sublayout_path.addWidget(QtWidgets.QLabel('/'))
sublayout_path.addWidget(self._value_widgets['Picture']['basename']) sublayout_path.addWidget(self._value_widgets['Picture']['basename'])
sublayout_path.addWidget(file_button) sublayout_path.addWidget(file_button)
layout.addRow(sublayout_path) layout.addRow(sublayout_path)
widget = QWidget() widget = QtWidgets.QWidget()
widget.setLayout(layout) widget.setLayout(layout)
return widget return widget
@@ -652,7 +642,7 @@ class PyQt5Settings(QFrame):
class PyQt5WaitMessage(QFrame): class PyQt5WaitMessage(QtWidgets.QFrame):
# With spinning wait clock, inspired by # With spinning wait clock, inspired by
# https://wiki.python.org/moin/PyQt/A%20full%20widget%20waiting%20indicator # https://wiki.python.org/moin/PyQt/A%20full%20widget%20waiting%20indicator
@@ -672,17 +662,17 @@ class PyQt5WaitMessage(QFrame):
def paintEvent(self, event): def paintEvent(self, event):
painter = QPainter(self) painter = QtGui.QPainter(self)
f = self.font() f = self.font()
f.setPixelSize(self.height() / 8) f.setPixelSize(self.height() / 8)
painter.setFont(f) painter.setFont(f)
rect = QRect(0, self.height() * 3 / 5, self.width(), self.height() * 3 / 10) rect = QtCore.QRect(0, self.height() * 3 / 5, self.width(), self.height() * 3 / 10)
painter.drawText(rect, Qt.AlignCenter, self._message) painter.drawText(rect, QtCore.Qt.AlignCenter, self._message)
painter.setRenderHint(QPainter.Antialiasing) painter.setRenderHint(QtGui.QPainter.Antialiasing)
painter.setPen(QPen(Qt.NoPen)) painter.setPen(QtGui.QPen(QtCore.Qt.NoPen))
center = (self.width() / 2, self.height() / 2) center = (self.width() / 2, self.height() / 2)
@@ -693,7 +683,7 @@ class PyQt5WaitMessage(QFrame):
distance = (pos - i) % dots distance = (pos - i) % dots
color = (distance + 1) / (dots + 1) * 255 color = (distance + 1) / (dots + 1) * 255
painter.setBrush(QBrush(QColor(color, color, color))) painter.setBrush(QtGui.QBrush(QtGui.QColor(color, color, color)))
painter.drawEllipse( painter.drawEllipse(
center[0] + 180 / dots * math.cos(2 * math.pi * i / dots) - 20, center[0] + 180 / dots * math.cos(2 * math.pi * i / dots) - 20,
@@ -716,7 +706,7 @@ class PyQt5WaitMessage(QFrame):
class PyQt5IdleMessage(QFrame): class PyQt5IdleMessage(QtWidgets.QFrame):
def __init__(self): def __init__(self):
@@ -732,19 +722,19 @@ class PyQt5IdleMessage(QFrame):
def paintEvent(self, event): def paintEvent(self, event):
painter = QPainter(self) painter = QtGui.QPainter(self)
f = self.font() f = self.font()
f.setPixelSize(self.height() / 5) f.setPixelSize(self.height() / 5)
painter.setFont(f) painter.setFont(f)
painter.drawText(event.rect(), Qt.AlignCenter, 'Hit the button!') painter.drawText(event.rect(), QtCore.Qt.AlignCenter, 'Hit the button!')
painter.end() painter.end()
class PyQt5GreeterMessage(QFrame): class PyQt5GreeterMessage(QtWidgets.QFrame):
def __init__(self, num_x, num_y): def __init__(self, num_x, num_y):
@@ -765,24 +755,24 @@ class PyQt5GreeterMessage(QFrame):
def paintEvent(self, event): def paintEvent(self, event):
painter = QPainter(self) painter = QtGui.QPainter(self)
f = self.font() f = self.font()
f.setPixelSize(self.height() / 5) f.setPixelSize(self.height() / 5)
painter.setFont(f) painter.setFont(f)
rect = QRect(0, self.height() * 1 / 5, self.width(), self.height() * 3 / 10) rect = QtCore.QRect(0, self.height() * 1 / 5, self.width(), self.height() * 3 / 10)
painter.drawText(rect, Qt.AlignCenter, self._title) painter.drawText(rect, QtCore.Qt.AlignCenter, self._title)
f.setPixelSize(self.height() / 8) f.setPixelSize(self.height() / 8)
painter.setFont(f) painter.setFont(f)
rect = QRect(0, self.height() * 3 / 5, self.width(), self.height() * 3 / 10) rect = QtCore.QRect(0, self.height() * 3 / 5, self.width(), self.height() * 3 / 10)
painter.drawText(rect, Qt.AlignCenter, self._text) painter.drawText(rect, QtCore.Qt.AlignCenter, self._text)
painter.end() painter.end()
class PyQt5CountdownMessage(QFrame): class PyQt5CountdownMessage(QtWidgets.QFrame):
def __init__(self, time, action): def __init__(self, time, action):
@@ -838,28 +828,28 @@ class PyQt5CountdownMessage(QFrame):
@picture.setter @picture.setter
def picture(self, pic): def picture(self, pic):
if not isinstance(pic, QImage): if not isinstance(pic, QtGui.QImage):
raise ValueError('picture must be a QImage') raise ValueError('picture must be a QtGui.QImage')
self._picture = pic self._picture = pic
def paintEvent(self, event): def paintEvent(self, event):
painter = QPainter(self) painter = QtGui.QPainter(self)
if self._picture != None: if self._picture != None:
pix = QPixmap.fromImage(self._picture) pix = QtGui.QPixmap.fromImage(self._picture)
pix = pix.scaled(self.size(), Qt.KeepAspectRatio, Qt.FastTransformation) pix = pix.scaled(self.size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.FastTransformation)
origin = ( (self.width() - pix.width()) // 2, origin = ( (self.width() - pix.width()) // 2,
(self.height() - pix.height()) // 2 ) (self.height() - pix.height()) // 2 )
painter.drawPixmap(QPoint(*origin), pix) painter.drawPixmap(QtCore.QPoint(*origin), pix)
painter.end() painter.end()
offset = ( (self.width() - self._bar.width()) // 2, offset = ( (self.width() - self._bar.width()) // 2,
(self.height() - self._bar.height()) // 2 ) (self.height() - self._bar.height()) // 2 )
self._bar.render(self, QPoint(*offset), self._bar.visibleRegion(), QWidget.DrawChildren) self._bar.render(self, QtCore.QPoint(*offset), self._bar.visibleRegion(), QtWidgets.QWidget.DrawChildren)
def showEvent(self, event): def showEvent(self, event):
@@ -880,7 +870,7 @@ class PyQt5CountdownMessage(QFrame):
class PyQt5PoseMessage(QFrame): class PyQt5PoseMessage(QtWidgets.QFrame):
def __init__(self): def __init__(self):
@@ -896,19 +886,19 @@ class PyQt5PoseMessage(QFrame):
def paintEvent(self, event): def paintEvent(self, event):
painter = QPainter(self) painter = QtGui.QPainter(self)
f = self.font() f = self.font()
f.setPixelSize(self.height() / 3) f.setPixelSize(self.height() / 3)
painter.setFont(f) painter.setFont(f)
painter.drawText(event.rect(), Qt.AlignCenter, 'Pose!') painter.drawText(event.rect(), QtCore.Qt.AlignCenter, 'Pose!')
painter.end() painter.end()
class PyQt5PictureMessage(QFrame): class PyQt5PictureMessage(QtWidgets.QFrame):
def __init__(self, picture): def __init__(self, picture):
@@ -926,17 +916,17 @@ class PyQt5PictureMessage(QFrame):
def paintEvent(self, event): def paintEvent(self, event):
painter = QPainter(self) painter = QtGui.QPainter(self)
if isinstance(self._picture, QImage): if isinstance(self._picture, QtGui.QImage):
pix = QPixmap.fromImage(self._picture) pix = QtGui.QPixmap.fromImage(self._picture)
else: else:
pix = QPixmap(self._picture) pix = QtGui.QPixmap(self._picture)
pix = pix.scaled(self.rect().size(), Qt.KeepAspectRatio, Qt.SmoothTransformation) pix = pix.scaled(self.rect().size(), QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
origin = ( (self.rect().width() - pix.width()) // 2, origin = ( (self.rect().width() - pix.width()) // 2,
(self.rect().height() - pix.height()) // 2 ) (self.rect().height() - pix.height()) // 2 )
painter.drawPixmap(QPoint(*origin), pix) painter.drawPixmap(QtCore.QPoint(*origin), pix)
painter.end() painter.end()

View File

@@ -10,6 +10,7 @@ from math import ceil
from PyQt5 import QtCore, QtGui, Qt, QtWidgets from PyQt5 import QtCore, QtGui, Qt, QtWidgets
class QRoundProgressBar(QtWidgets.QWidget): class QRoundProgressBar(QtWidgets.QWidget):
StyleDonut = 1 StyleDonut = 1
@@ -33,7 +34,7 @@ class QRoundProgressBar(QtWidgets.QWidget):
self.nullPosition = self.PositionTop self.nullPosition = self.PositionTop
self.barStyle = self.StyleDonut self.barStyle = self.StyleDonut
self.outlinePenWidth =1 self.outlinePenWidth = 1
self.dataPenWidth = 1 self.dataPenWidth = 1
self.rebuildBrush = False self.rebuildBrush = False
self.format = "%p%" self.format = "%p%"
@@ -124,7 +125,8 @@ class QRoundProgressBar(QtWidgets.QWidget):
outerRadius = min(self.width(), self.height()) outerRadius = min(self.width(), self.height())
baseRect = QtCore.QRectF(1, 1, outerRadius-2, outerRadius-2) baseRect = QtCore.QRectF(1, 1, outerRadius-2, outerRadius-2)
buffer = QtGui.QImage(outerRadius, outerRadius, QtGui.QImage.Format_ARGB32) buffer = QtGui.QImage(outerRadius, outerRadius,
QtGui.QImage.Format_ARGB32)
buffer.fill(0) buffer.fill(0)
p = QtGui.QPainter(buffer) p = QtGui.QPainter(buffer)
@@ -162,11 +164,13 @@ class QRoundProgressBar(QtWidgets.QWidget):
def drawBase(self, p, baseRect): def drawBase(self, p, baseRect):
bs = self.barStyle bs = self.barStyle
if bs == self.StyleDonut: if bs == self.StyleDonut:
p.setPen(QtGui.QPen(self.palette().shadow().color(), self.outlinePenWidth)) p.setPen(QtGui.QPen(self.palette().shadow().color(),
self.outlinePenWidth))
p.setBrush(self.palette().base()) p.setBrush(self.palette().base())
p.drawEllipse(baseRect) p.drawEllipse(baseRect)
elif bs == self.StylePie: elif bs == self.StylePie:
p.setPen(QtGui.QPen(self.palette().base().color(), self.outlinePenWidth)) p.setPen(QtGui.QPen(self.palette().base().color(),
self.outlinePenWidth))
p.setBrush(self.palette().base()) p.setBrush(self.palette().base())
p.drawEllipse(baseRect) p.drawEllipse(baseRect)
elif bs == self.StyleLine: elif bs == self.StyleLine:
@@ -174,13 +178,17 @@ class QRoundProgressBar(QtWidgets.QWidget):
color.setAlpha(100) color.setAlpha(100)
brush = self.palette().base() brush = self.palette().base()
brush.setColor(color) brush.setColor(color)
p.setPen(QtGui.QPen(self.palette().base().color(), self.outlinePenWidth)) p.setPen(QtGui.QPen(self.palette().base().color(),
self.outlinePenWidth))
p.setBrush(brush) p.setBrush(brush)
# p.drawEllipse(baseRect) # p.drawEllipse(baseRect)
# p.setPen(QtGui.QPen(self.palette().base().color(), self.outlinePenWidth)) # p.setPen(QtGui.QPen(self.palette().base().color(),
# self.outlinePenWidth))
# p.setBrush(Qt.Qt.NoBrush) # p.setBrush(Qt.Qt.NoBrush)
p.drawEllipse(baseRect.adjusted(self.outlinePenWidth/2, self.outlinePenWidth/2, -self.outlinePenWidth/2, -self.outlinePenWidth/2)) p.drawEllipse(baseRect.adjusted(self.outlinePenWidth/2,
self.outlinePenWidth/2,
-self.outlinePenWidth/2,
-self.outlinePenWidth/2))
def drawValue(self, p, baseRect, value, arcLength): def drawValue(self, p, baseRect, value, arcLength):
# nothing to draw # nothing to draw
@@ -189,9 +197,13 @@ class QRoundProgressBar(QtWidgets.QWidget):
# for Line style # for Line style
if self.barStyle == self.StyleLine: if self.barStyle == self.StyleLine:
p.setPen(QtGui.QPen(self.palette().highlight().color(), self.dataPenWidth)) p.setPen(QtGui.QPen(self.palette().highlight().color(),
self.dataPenWidth))
p.setBrush(Qt.Qt.NoBrush) p.setBrush(Qt.Qt.NoBrush)
p.drawArc(baseRect.adjusted(self.outlinePenWidth/2, self.outlinePenWidth/2, -self.outlinePenWidth/2, -self.outlinePenWidth/2), p.drawArc(baseRect.adjusted(self.outlinePenWidth/2,
self.outlinePenWidth/2,
-self.outlinePenWidth/2,
-self.outlinePenWidth/2),
self.nullPosition * 16, self.nullPosition * 16,
-arcLength * 16) -arcLength * 16)
return return
@@ -206,7 +218,8 @@ class QRoundProgressBar(QtWidgets.QWidget):
dataPath.lineTo(baseRect.center()) dataPath.lineTo(baseRect.center())
p.setBrush(self.palette().highlight()) p.setBrush(self.palette().highlight())
p.setPen(QtGui.QPen(self.palette().shadow().color(), self.dataPenWidth)) p.setPen(QtGui.QPen(self.palette().shadow().color(),
self.dataPenWidth))
p.drawPath(dataPath) p.drawPath(dataPath)
def calculateInnerRect(self, baseRect, outerRadius): def calculateInnerRect(self, baseRect, outerRadius):
@@ -239,8 +252,6 @@ class QRoundProgressBar(QtWidgets.QWidget):
# !!! to revise # !!! to revise
f = self.font() f = self.font()
# f.setPixelSize(innerRadius * max(0.05, (0.35 - self.decimals * 0.08)))
# f.setPixelSize(innerRadius * 1.8 / len(text))
f.setPixelSize(innerRadius * 0.8 / len(text)) f.setPixelSize(innerRadius * 0.8 / len(text))
p.setFont(f) p.setFont(f)
@@ -257,8 +268,8 @@ class QRoundProgressBar(QtWidgets.QWidget):
textToDraw = textToDraw.replace("%v", format_string.format(value)) textToDraw = textToDraw.replace("%v", format_string.format(value))
if self.updateFlags & self.UF_PERCENT: if self.updateFlags & self.UF_PERCENT:
percent = (value - self.min) / (self.max - self.min) * 100.0 perc = (value - self.min) / (self.max - self.min) * 100.0
textToDraw = textToDraw.replace("%p", format_string.format(percent)) textToDraw = textToDraw.replace("%p", format_string.format(perc))
if self.updateFlags & self.UF_MAX: if self.updateFlags & self.UF_MAX:
m = self.max - self.min + 1 m = self.max - self.min + 1
@@ -267,7 +278,7 @@ class QRoundProgressBar(QtWidgets.QWidget):
return textToDraw return textToDraw
def valueFormatChanged(self): def valueFormatChanged(self):
self.updateFlags = 0; self.updateFlags = 0
if "%v" in self.format: if "%v" in self.format:
self.updateFlags |= self.UF_VALUE self.updateFlags |= self.UF_VALUE
@@ -285,7 +296,7 @@ class QRoundProgressBar(QtWidgets.QWidget):
self.rebuildBrush = False self.rebuildBrush = False
dataBrush = QtGui.QConicalGradient() dataBrush = QtGui.QConicalGradient()
dataBrush.setCenter(0.5,0.5) dataBrush.setCenter(0.5, 0.5)
dataBrush.setCoordinateMode(QtGui.QGradient.StretchToDeviceMode) dataBrush.setCoordinateMode(QtGui.QGradient.StretchToDeviceMode)
for pos, color in self.gradientData: for pos, color in self.gradientData:
@@ -296,4 +307,4 @@ class QRoundProgressBar(QtWidgets.QWidget):
p = self.palette() p = self.palette()
p.setBrush(QtGui.QPalette.Highlight, dataBrush) p.setBrush(QtGui.QPalette.Highlight, dataBrush)
self.setPalette(p) self.setPalette(p)

View File

@@ -1,13 +1,11 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from .GuiState import * # noqa
from .GuiState import * from .GuiPostprocess import * # noqa
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'), )
class Gui: class Gui:
@@ -16,9 +14,6 @@ class Gui:
pass pass
def run(self, camera_conn, worker_queue): def run(self, camera_conn, worker_queue):
raise NotImplementedError() raise NotImplementedError()

View File

@@ -7,9 +7,10 @@ try:
except DistributionNotFound: except DistributionNotFound:
__version__ = 'unknown' __version__ = 'unknown'
import sys import logging
import logging.handlers
import multiprocessing as mp import multiprocessing as mp
import logging, logging.handlers import sys
from . import camera, gui from . import camera, gui
from .Config import Config from .Config import Config
@@ -17,6 +18,7 @@ from .Photobooth import Photobooth
from .util import lookup_and_import from .util import lookup_and_import
from .Worker import Worker from .Worker import Worker
class CameraProcess(mp.Process): class CameraProcess(mp.Process):
def __init__(self, config, conn, worker_queue): def __init__(self, config, conn, worker_queue):
@@ -28,7 +30,6 @@ class CameraProcess(mp.Process):
self.conn = conn self.conn = conn
self.worker_queue = worker_queue self.worker_queue = worker_queue
def run_camera(self): def run_camera(self):
try: try:
@@ -40,7 +41,7 @@ class CameraProcess(mp.Process):
return photobooth.run() return photobooth.run()
except BaseException as e: except BaseException as e:
self.conn.send( gui.ErrorState('Camera error', str(e)) ) self.conn.send(gui.ErrorState('Camera error', str(e)))
event = self.conn.recv() event = self.conn.recv()
if str(event) in ('cancel', 'ack'): if str(event) in ('cancel', 'ack'):
return 123 return 123
@@ -48,7 +49,6 @@ class CameraProcess(mp.Process):
logging.error('Unknown event received: %s', str(event)) logging.error('Unknown event received: %s', str(event))
raise RuntimeError('Unknown event received', str(event)) raise RuntimeError('Unknown event received', str(event))
def run(self): def run(self):
status_code = 123 status_code = 123
@@ -76,7 +76,6 @@ class WorkerProcess(mp.Process):
self.cfg = config self.cfg = config
self.queue = queue self.queue = queue
def run(self): def run(self):
sys.exit(Worker(self.cfg, self.queue).run()) sys.exit(Worker(self.cfg, self.queue).run())
@@ -93,10 +92,10 @@ class GuiProcess(mp.Process):
self.conn = conn self.conn = conn
self.queue = queue 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, self.queue)) sys.exit(Gui(self.argv, self.cfg).run(self.conn, self.queue))
@@ -107,7 +106,7 @@ def run(argv):
# Load configuration # Load configuration
config = Config('photobooth.cfg') config = Config('photobooth.cfg')
# Create communication objects: # Create communication objects:
# 1. We use a pipe to connect GUI and camera process # 1. We use a pipe to connect GUI and camera process
# 2. We use a queue to feed tasks to the postprocessing process # 2. We use a queue to feed tasks to the postprocessing process
gui_conn, camera_conn = mp.Pipe() gui_conn, camera_conn = mp.Pipe()
@@ -129,7 +128,7 @@ def run(argv):
# Close endpoints # Close endpoints
gui_conn.close() gui_conn.close()
camera_conn.close() camera_conn.close()
# Wait for processes to finish # Wait for processes to finish
gui_proc.join() gui_proc.join()
worker_queue.put('teardown') worker_queue.put('teardown')
@@ -150,12 +149,12 @@ def main(argv):
ch.setFormatter(formatter) ch.setFormatter(formatter)
# create file handler and set format # create file handler and set format
fh = logging.handlers.TimedRotatingFileHandler('photobooth.log', fh = logging.handlers.TimedRotatingFileHandler('photobooth.log', when='d',
when='d', interval=1, backupCount=10) interval=1, backupCount=10)
fh.setFormatter(formatter) fh.setFormatter(formatter)
# Apply config # Apply config
logging.basicConfig(level=log_level, handlers=(ch,fh)) logging.basicConfig(level=log_level, handlers=(ch, fh))
# Set of known status codes which trigger a restart of the application # Set of known status codes which trigger a restart of the application
known_status_codes = { known_status_codes = {

View File

@@ -5,12 +5,12 @@ import logging
from PIL import ImageQt from PIL import ImageQt
from PyQt5.QtCore import Qt, QPoint, QSizeF from PyQt5 import QtCore, QtGui
from PyQt5.QtGui import QPageSize, QPainter, QPixmap
from PyQt5.QtPrintSupport import QPrinter from PyQt5.QtPrintSupport import QPrinter
from . import Printer from . import Printer
class PrinterPyQt5(Printer): class PrinterPyQt5(Printer):
def __init__(self, page_size, print_pdf=False): def __init__(self, page_size, print_pdf=False):
@@ -18,7 +18,8 @@ class PrinterPyQt5(Printer):
super().__init__(page_size) super().__init__(page_size)
self._printer = QPrinter(QPrinter.HighResolution) self._printer = QPrinter(QPrinter.HighResolution)
self._printer.setPageSize(QPageSize(QSizeF(*page_size), QPageSize.Millimeter)) self._printer.setPageSize(QtGui.QPageSize(QtCore.QSizeF(*page_size),
QtGui.QPageSize.Millimeter))
self._printer.setColorMode(QPrinter.Color) self._printer.setColorMode(QPrinter.Color)
logging.info('Using printer "%s"', self._printer.printerName()) logging.info('Using printer "%s"', self._printer.printerName())
@@ -30,21 +31,21 @@ class PrinterPyQt5(Printer):
self._printer.setOutputFormat(QPrinter.PdfFormat) self._printer.setOutputFormat(QPrinter.PdfFormat)
self._printer.setFullPage(True) self._printer.setFullPage(True)
def print(self, picture): def print(self, picture):
if self._print_pdf: if self._print_pdf:
self._printer.setOutputFileName('print_' + str(self._counter) + '.pdf') self._printer.setOutputFileName('print_%d.pdf' % self._counter)
self._counter += 1 self._counter += 1
img = ImageQt.ImageQt(picture) img = ImageQt.ImageQt(picture)
img = img.scaled(self._printer.pageRect().size(), Qt.KeepAspectRatio, img = img.scaled(self._printer.pageRect().size(),
Qt.SmoothTransformation) QtCore.Qt.KeepAspectRatio,
QtCore.Qt.SmoothTransformation)
printable_size = self._printer.pageRect(QPrinter.DevicePixel) printable_size = self._printer.pageRect(QPrinter.DevicePixel)
origin = ( (printable_size.width() - img.width()) // 2, origin = ((printable_size.width() - img.width()) // 2,
(printable_size.height() - img.height()) // 2 ) (printable_size.height() - img.height()) // 2)
painter = QPainter(self._printer) painter = QtGui.QPainter(self._printer)
painter.drawImage(QPoint(*origin), img) painter.drawImage(QtCore.QPoint(*origin), img)
painter.end() painter.end()

View File

@@ -13,13 +13,11 @@ class Printer:
self.pageSize = page_size self.pageSize = page_size
@property @property
def pageSize(self): def pageSize(self):
return self._page_size return self._page_size
@pageSize.setter @pageSize.setter
def pageSize(self, page_size): def pageSize(self, page_size):
@@ -28,8 +26,6 @@ class Printer:
self._page_size = page_size self._page_size = page_size
def print(self, picture): def print(self, picture):
raise NotImplementedError('print function not implemented!') raise NotImplementedError('print function not implemented!')

View File

@@ -1,23 +1,22 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import importlib import importlib
def lookup_and_import(module_list, name, package=None): def lookup_and_import(module_list, name, package=None):
result = next(((mod_name, class_name) result = next(((mod_name, class_name)
for config_name, mod_name, class_name in module_list for config_name, mod_name, class_name in module_list
if name == config_name), None) if name == config_name), None)
if package == None: if package is None:
import_module = importlib.import_module('photobooth.' + result[0]) import_module = importlib.import_module('photobooth.' + result[0])
else: else:
import_module = importlib.import_module( import_module = importlib.import_module(
'photobooth.' + package + '.' + result[0]) 'photobooth.' + package + '.' + result[0])
if result[1] == None: if result[1] is None:
return import_module return import_module
else: else:
return getattr(import_module, result[1]) return getattr(import_module, result[1])