From 1da57c5bfc1ea0f7332aeb7bb9579d0fee78424f Mon Sep 17 00:00:00 2001 From: Balthasar Reuter Date: Thu, 8 Feb 2018 21:42:05 +0100 Subject: [PATCH] Removed files from previous version --- camera.py | 133 --------------- events.py | 49 ------ gui.py | 245 ---------------------------- photobooth.py | 425 ------------------------------------------------ photobooth.sh | 14 -- set-time.py | 100 ------------ slideshow.py | 134 --------------- transparent.msk | 4 - transparent.xbm | 6 - 9 files changed, 1110 deletions(-) delete mode 100644 camera.py delete mode 100644 events.py delete mode 100644 gui.py delete mode 100755 photobooth.py delete mode 100755 photobooth.sh delete mode 100755 set-time.py delete mode 100755 slideshow.py delete mode 100644 transparent.msk delete mode 100644 transparent.xbm diff --git a/camera.py b/camera.py deleted file mode 100644 index 3e79296..0000000 --- a/camera.py +++ /dev/null @@ -1,133 +0,0 @@ -#!/usr/bin/env python -# Created by br@re-web.eu, 2015 - -import subprocess - -cv_enabled = False -gphoto2cffi_enabled = False -piggyphoto_enabled = False - -try: - import cv2 as cv - cv_enabled = True - print('OpenCV available') -except ImportError: - pass - -try: - import gphoto2cffi as gp - gpExcept = gp.errors.GPhoto2Error - gphoto2cffi_enabled = True - print('Gphoto2cffi available') -except ImportError: - pass - -if not gphoto2cffi_enabled: - try: - import piggyphoto as gp - gpExcept = gp.libgphoto2error - piggyphoto_enabled = True - print('Piggyphoto available') - except ImportError: - pass - -class CameraException(Exception): - """Custom exception class to handle camera class errors""" - def __init__(self, message, recoverable=False): - self.message = message - self.recoverable = recoverable - - -class Camera_cv: - def __init__(self, picture_size): - if cv_enabled: - self.cap = cv.VideoCapture(0) - self.cap.set(3, picture_size[0]) - self.cap.set(4, picture_size[1]) - - def has_preview(self): - return True - - def take_preview(self, filename="/tmp/preview.jpg"): - self.take_picture(filename) - - def take_picture(self, filename="/tmp/picture.jpg"): - if cv_enabled: - r, frame = self.cap.read() - cv.imwrite(filename, frame) - return filename - else: - raise CameraException("OpenCV not available!") - - def set_idle(self): - pass - - -class Camera_gPhoto: - """Camera class providing functionality to take pictures using gPhoto 2""" - - def __init__(self, picture_size): - self.picture_size = picture_size - # Print the capabilities of the connected camera - try: - if gphoto2cffi_enabled: - self.cap = gp.Camera() - elif piggyphoto_enabled: - self.cap = gp.camera() - print(self.cap.abilities) - else: - print(self.call_gphoto("-a", "/dev/null")) - except CameraException as e: - print('Warning: Listing camera capabilities failed (' + e.message + ')') - except gpExcept as e: - print('Warning: Listing camera capabilities failed (' + e.message + ')') - - def call_gphoto(self, action, filename): - # Try to run the command - try: - cmd = "gphoto2 --force-overwrite --quiet " + action + " --filename " + filename - output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT) - if "ERROR" in output: - raise subprocess.CalledProcessError(returncode=0, cmd=cmd, output=output) - except subprocess.CalledProcessError as e: - if "EOS Capture failed: 2019" in e.output or "Perhaps no focus" in e.output: - raise CameraException("Can't focus!\nMove a little bit!", True) - elif "No camera found" in e.output: - raise CameraException("No (supported) camera detected!", False) - elif "command not found" in e.output: - raise CameraException("gPhoto2 not found!", False) - else: - raise CameraException("Unknown error!\n" + '\n'.join(e.output.split('\n')[1:3]), False) - return output - - def has_preview(self): - return gphoto2cffi_enabled or piggyphoto_enabled - - def take_preview(self, filename="/tmp/preview.jpg"): - if gphoto2cffi_enabled: - self._save_picture(filename, self.cap.get_preview()) - elif piggyphoto_enabled: - self.cap.capture_preview(filename) - else: - raise CameraException("No preview supported!") - - def take_picture(self, filename="/tmp/picture.jpg"): - if gphoto2cffi_enabled: - self._save_picture(filename, self.cap.capture()) - elif piggyphoto_enabled: - self.cap.capture_image(filename) - else: - self.call_gphoto("--capture-image-and-download", filename) - return filename - - def _save_picture(self, filename, data): - f = open(filename, 'wb') - f.write(data) - f.close() - - def set_idle(self): - if gphoto2cffi_enabled: - self.cap._get_config()['actions']['viewfinder'].set(False) - elif piggyphoto_enabled: - # This doesn't work... - self.cap.config.main.actions.viewfinder.value = 0 diff --git a/events.py b/events.py deleted file mode 100644 index 4bfe035..0000000 --- a/events.py +++ /dev/null @@ -1,49 +0,0 @@ -#!/usr/bin/env python -# Created by br _at_ re-web _dot_ eu, 2015 - -try: - import RPi.GPIO as GPIO - gpio_enabled = True -except ImportError: - gpio_enabled = False - - -class Event: - def __init__(self, type, value): - """type 0: quit - 1: keystroke - 2: mouseclick - 3: gpio - """ - self.type = type - self.value = value - -class Rpi_GPIO: - def __init__(self, handle_function, input_channels = [], output_channels = []): - if gpio_enabled: - # Display initial information - print("Your Raspberry Pi is board revision " + str(GPIO.RPI_INFO['P1_REVISION'])) - print("RPi.GPIO version is " + str(GPIO.VERSION)) - - # Choose BCM numbering system - GPIO.setmode(GPIO.BCM) - - # Setup the input channels - for input_channel in input_channels: - GPIO.setup(input_channel, GPIO.IN, pull_up_down=GPIO.PUD_UP) - GPIO.add_event_detect(input_channel, GPIO.RISING, callback=handle_function, bouncetime=200) - - # Setup the output channels - for output_channel in output_channels: - GPIO.setup(output_channel, GPIO.OUT) - GPIO.output(output_channel, GPIO.LOW) - else: - print("Warning: RPi.GPIO could not be loaded. GPIO disabled.") - - def teardown(self): - if gpio_enabled: - GPIO.cleanup() - - def set_output(self, channel, value=0): - if gpio_enabled: - GPIO.output(channel, GPIO.HIGH if value==1 else GPIO.LOW) diff --git a/gui.py b/gui.py deleted file mode 100644 index 4468e9d..0000000 --- a/gui.py +++ /dev/null @@ -1,245 +0,0 @@ -#!/usr/bin/env python -# Created by br _at_ re-web _dot_ eu, 2015 - -from __future__ import division - -import pygame - -try: - import pygame.fastevent as EventModule -except ImportError: - import pygame.event as EventModule - -from events import Event - -class GuiException(Exception): - """Custom exception class to handle GUI class errors""" - -class GUI_PyGame: - """A GUI class using PyGame""" - - def __init__(self, name, size, hide_mouse=True): - # Call init routines - pygame.init() - if hasattr(EventModule, 'init'): - EventModule.init() - - # Window name - pygame.display.set_caption(name) - - # Hide mouse cursor - if hide_mouse: - pygame.mouse.set_cursor(*pygame.cursors.load_xbm('transparent.xbm','transparent.msk')) - - # Store screen and size - self.size = size - self.screen = pygame.display.set_mode(size, pygame.FULLSCREEN) - - # Clear screen - self.clear() - self.apply() - - def clear(self, color=(0,0,0)): - self.screen.fill(color) - self.surface_list = [] - - def apply(self): - for surface in self.surface_list: - self.screen.blit(surface[0], surface[1]) - pygame.display.update() - - def get_size(self): - return self.size - - def trigger_event(self, event_channel): - EventModule.post(EventModule.Event(pygame.USEREVENT, channel=event_channel)) - - def show_picture(self, filename, size=(0,0), offset=(0,0), flip=False): - # Use window size if none given - if size == (0,0): - size = self.size - try: - # Load image from file - image = pygame.image.load(filename) - except pygame.error as e: - raise GuiException("ERROR: Can't open image '" + filename + "': " + e.message) - # Extract image size and determine scaling - image_size = image.get_rect().size - image_scale = min([min(a,b)/b for a,b in zip(size, image_size)]) - # New image size - new_size = [int(a*image_scale) for a in image_size] - # Update offset - offset = tuple(a+int((b-c)/2) for a,b,c in zip(offset, size, new_size)) - # Apply scaling and display picture - image = pygame.transform.scale(image, new_size).convert() - # Create surface and blit the image to it - surface = pygame.Surface(new_size) - surface.blit(image, (0,0)) - if flip: - surface = pygame.transform.flip(surface, True, False) - self.surface_list.append((surface, offset)) - - def show_message(self, msg, color=(0,0,0), bg=(230,230,230), transparency=True, outline=(245,245,245)): - # Choose font - font = pygame.font.Font(None, 144) - # Wrap and render text - wrapped_text, text_height = self.wrap_text(msg, font, self.size) - rendered_text = self.render_text(wrapped_text, text_height, 1, 1, font, color, bg, transparency, outline) - - self.surface_list.append((rendered_text, (0,0))) - - def show_button(self, text, pos, size=(0,0), color=(230,230,230), bg=(0,0,0), transparency=True, outline=(230,230,230)): - # Choose font - font = pygame.font.Font(None, 72) - text_size = font.size(text) - if size == (0,0): - size = (text_size[0] + 4, text_size[1] + 4) - offset = ( (size[0] - text_size[0]) // 2, (size[1] - text_size[1]) // 2 ) - - # Create Surface object and fill it with the given background - surface = pygame.Surface(self.size) - surface.fill(bg) - - # Render text - rendered_text = font.render(text, 1, color) - surface.blit(rendered_text, pos) - - # Render outline - pygame.draw.rect(surface, outline, (pos[0]-offset[0], pos[1]-offset[0], size[0], size[1]), 1) - - # Make background color transparent - if transparency: - surface.set_colorkey(bg) - - self.surface_list.append((surface, (0,0))) - - def wrap_text(self, msg, font, size): - final_lines = [] # resulting wrapped text - requested_lines = msg.splitlines() # wrap input along line breaks - accumulated_height = 0 # accumulated height - - # Form a series of lines - for requested_line in requested_lines: - # Handle too long lines - if font.size(requested_line)[0] > size[0]: - # Split at white spaces - words = requested_line.split(' ') - # if any of our words are too long to fit, trim them - for word in words: - while font.size(word)[0] >= size[0]: - word = word[:-1] - # Start a new line - accumulated_line = "" - # Put words on the line as long as they fit - for word in words: - test_line = accumulated_line + word + " " - # Build the line while the words fit. - if font.size(test_line)[0] < size[0]: - accumulated_line = test_line - else: - # Start a new line - line_height = font.size(accumulated_line)[1] - if accumulated_height + line_height > size[1]: - break - else: - accumulated_height += line_height - final_lines.append(accumulated_line) - accumulated_line = word + " " - # Finish requested_line - line_height = font.size(accumulated_line)[1] - if accumulated_height + line_height > size[1]: - break - else: - accumulated_height += line_height - final_lines.append(accumulated_line) - # Line fits as it is - else: - accumulated_height += font.size(requested_line)[1] - final_lines.append(requested_line) - - # Check height of wrapped text - if accumulated_height >= size[1]: - raise GuiException("Wrapped text is too high to fit.") - - return final_lines, accumulated_height - - def render_text(self, text, text_height, valign, halign, font, color, bg, transparency, outline): - # Determine vertical position - if valign == 0: # top aligned - voffset = 0 - elif valign == 1: # centered - voffset = int((self.size[1] - text_height) / 2) - elif valign == 2: # bottom aligned - voffset = self.size[1] - text_height - else: - raise GuiException("Invalid valign argument: " + str(valign)) - - # Create Surface object and fill it with the given background - surface = pygame.Surface(self.size) - surface.fill(bg) - - # Blit one line after another - accumulated_height = 0 - for line in text: - maintext = font.render(line, 1, color) - shadow = font.render(line, 1, outline) - if halign == 0: # left aligned - hoffset = 0 - elif halign == 1: # centered - hoffset = (self.size[0] - maintext.get_width()) / 2 - elif halign == 2: # right aligned - hoffset = rect.width - maintext.get_width() - else: - raise GuiException("Invalid halign argument: " + str(justification)) - pos = (hoffset, voffset + accumulated_height) - # Outline - surface.blit(shadow, (pos[0]-1,pos[1]-1)) - surface.blit(shadow, (pos[0]-1,pos[1]+1)) - surface.blit(shadow, (pos[0]+1,pos[1]-1)) - surface.blit(shadow, (pos[0]+1,pos[1]+1)) - # Text - surface.blit(maintext, pos) - accumulated_height += font.size(line)[1] - - # Make background color transparent - if transparency: - surface.set_colorkey(bg) - - # Return the rendered surface - return surface - - def convert_event(self, event): - if event.type == pygame.QUIT: - return True, Event(0, 0) - elif event.type == pygame.KEYDOWN: - return True, Event(1, event.key) - elif event.type == pygame.MOUSEBUTTONUP: - return True, Event(2, (event.button, event.pos)) - elif event.type >= pygame.USEREVENT: - return True, Event(3, event.channel) - else: - return False, '' - - def check_for_event(self): - for event in EventModule.get(): - r, e = self.convert_event(event) - if r: - return r, e - return False, '' - - def wait_for_event(self): - # Repeat until a relevant event happened - while True: - # Discard all input that happened before entering the loop - EventModule.get() - - # Wait for event - event = EventModule.wait() - - # Return Event-Object - r, e = self.convert_event(event) - if r: - return e - - def teardown(self): - pygame.quit() diff --git a/photobooth.py b/photobooth.py deleted file mode 100755 index 0fb619e..0000000 --- a/photobooth.py +++ /dev/null @@ -1,425 +0,0 @@ -#!/usr/bin/env python -# Created by br _at_ re-web _dot_ eu, 2015-2016 - -import os -from datetime import datetime -from glob import glob -from sys import exit -from time import sleep, clock - -from PIL import Image - -from gui import GUI_PyGame as GuiModule -# from camera import CameraException, Camera_cv as CameraModule -from camera import CameraException, Camera_gPhoto as CameraModule -from slideshow import Slideshow -from events import Rpi_GPIO as GPIO - -##################### -### Configuration ### -##################### - -# Screen size -display_size = (1024, 600) - -# Maximum size of assembled image -image_size = (2352, 1568) - -# Size of pictures in the assembled image -thumb_size = (1176, 784) - -# Image basename -picture_basename = datetime.now().strftime("%Y-%m-%d/pic") - -# GPIO channel of switch to shutdown the Photobooth -gpio_shutdown_channel = 24 # pin 18 in all Raspi-Versions - -# GPIO channel of switch to take pictures -gpio_trigger_channel = 23 # pin 16 in all Raspi-Versions - -# GPIO output channel for (blinking) lamp -gpio_lamp_channel = 4 # pin 7 in all Raspi-Versions - -# Waiting time in seconds for posing -pose_time = 3 - -# Display time for assembled picture -display_time = 10 - -# Show a slideshow of existing pictures when idle -idle_slideshow = True - -# Display time of pictures in the slideshow -slideshow_display_time = 5 - -############### -### Classes ### -############### - -class PictureList: - """A simple helper class. - - It provides the filenames for the assembled pictures and keeps count - of taken and previously existing pictures. - """ - - def __init__(self, basename): - """Initialize filenames to the given basename and search for - existing files. Set the counter accordingly. - """ - - # Set basename and suffix - self.basename = basename - self.suffix = ".jpg" - self.count_width = 5 - - # Ensure directory exists - dirname = os.path.dirname(self.basename) - if not os.path.exists(dirname): - os.makedirs(dirname) - - # Find existing files - count_pattern = "[0-9]" * self.count_width - pictures = glob(self.basename + count_pattern + self.suffix) - - # Get number of latest file - if len(pictures) == 0: - self.counter = 0 - else: - pictures.sort() - last_picture = pictures[-1] - self.counter = int(last_picture[-(self.count_width+len(self.suffix)):-len(self.suffix)]) - - # Print initial infos - print("Info: Number of last existing file: " + str(self.counter)) - print("Info: Saving assembled pictures as: " + self.basename + "XXXXX.jpg") - - def get(self, count): - return self.basename + str(count).zfill(self.count_width) + self.suffix - - def get_last(self): - return self.get(self.counter) - - def get_next(self): - self.counter += 1 - return self.get(self.counter) - - -class Photobooth: - """The main class. - - It contains all the logic for the photobooth. - """ - - def __init__(self, display_size, picture_basename, picture_size, pose_time, display_time, - trigger_channel, shutdown_channel, lamp_channel, idle_slideshow, slideshow_display_time): - self.display = GuiModule('Photobooth', display_size) - self.pictures = PictureList(picture_basename) - self.camera = CameraModule(picture_size) - - self.pic_size = picture_size - self.pose_time = pose_time - self.display_time = display_time - - self.trigger_channel = trigger_channel - self.shutdown_channel = shutdown_channel - self.lamp_channel = lamp_channel - - self.idle_slideshow = idle_slideshow - if self.idle_slideshow: - self.slideshow_display_time = slideshow_display_time - self.slideshow = Slideshow(display_size, display_time, - os.path.dirname(os.path.realpath(picture_basename))) - - input_channels = [ trigger_channel, shutdown_channel ] - output_channels = [ lamp_channel ] - self.gpio = GPIO(self.handle_gpio, input_channels, output_channels) - - def teardown(self): - self.display.clear() - self.display.show_message("Shutting down...") - self.display.apply() - self.gpio.set_output(self.lamp_channel, 0) - sleep(0.5) - self.display.teardown() - self.gpio.teardown() - exit(0) - - def _run_plain(self): - while True: - self.camera.set_idle() - - # Display default message - self.display.clear() - self.display.show_message("Hit the button!") - self.display.apply() - - # Wait for an event and handle it - event = self.display.wait_for_event() - self.handle_event(event) - - def _run_slideshow(self): - while True: - self.camera.set_idle() - self.slideshow.display_next("Hit the button!") - tic = clock() - while clock() - tic < self.slideshow_display_time: - self.check_and_handle_events() - - def run(self): - while True: - try: - # Enable lamp - self.gpio.set_output(self.lamp_channel, 1) - - # Select idle screen type - if self.idle_slideshow: - self._run_slideshow() - else: - self._run_plain() - - # Catch exceptions and display message - except CameraException as e: - self.handle_exception(e.message) - # Do not catch KeyboardInterrupt and SystemExit - except (KeyboardInterrupt, SystemExit): - raise - except Exception as e: - print('SERIOUS ERROR: ' + repr(e)) - self.handle_exception("SERIOUS ERROR!") - - def check_and_handle_events(self): - r, e = self.display.check_for_event() - while r: - self.handle_event(e) - r, e = self.display.check_for_event() - - def handle_gpio(self, channel): - if channel in [ self.trigger_channel, self.shutdown_channel ]: - self.display.trigger_event(channel) - - def handle_event(self, event): - if event.type == 0: - self.teardown() - elif event.type == 1: - self.handle_keypress(event.value) - elif event.type == 2: - self.handle_mousebutton(event.value[0], event.value[1]) - elif event.type == 3: - self.handle_gpio_event(event.value) - - def handle_keypress(self, key): - """Implements the actions for the different keypress events""" - # Exit the application - if key == ord('q'): - self.teardown() - # Take pictures - elif key == ord('c'): - self.take_picture() - - def handle_mousebutton(self, key, pos): - """Implements the actions for the different mousebutton events""" - # Take a picture - if key == 1: - self.take_picture() - - def handle_gpio_event(self, channel): - """Implements the actions taken for a GPIO event""" - if channel == self.trigger_channel: - self.take_picture() - elif channel == self.shutdown_channel: - self.teardown() - - def handle_exception(self, msg): - """Displays an error message and returns""" - self.display.clear() - print("Error: " + msg) - self.display.show_message("ERROR:\n\n" + msg) - self.display.apply() - sleep(3) - - - def assemble_pictures(self, input_filenames): - """Assembles four pictures into a 2x2 grid - - It assumes, all original pictures have the same aspect ratio as - the resulting image. - - For the thumbnail sizes we have: - h = (H - 2 * a - 2 * b) / 2 - w = (W - 2 * a - 2 * b) / 2 - - W - |---------------------------------------| - - --- +---+-------------+---+-------------+---+ --- - | | | | a - | | +-------------+ +-------------+ | --- - | | | | | | | | - | | | 0 | | 1 | | | h - | | | | | | | | - | | +-------------+ +-------------+ | --- - H | | | | 2*b - | | +-------------+ +-------------+ | --- - | | | | | | | | - | | | 2 | | 3 | | | h - | | | | | | | | - | | +-------------+ +-------------+ | --- - | | | | a - --- +---+-------------+---+-------------+---+ --- - - |---|-------------|---|-------------|---| - a w 2*b w a - """ - - # Thumbnail size of pictures - outer_border = 50 - inner_border = 20 - thumb_box = ( int( self.pic_size[0] / 2 ) , - int( self.pic_size[1] / 2 ) ) - thumb_size = ( thumb_box[0] - outer_border - inner_border , - thumb_box[1] - outer_border - inner_border ) - - # Create output image with white background - output_image = Image.new('RGB', self.pic_size, (255, 255, 255)) - - # Image 0 - img = Image.open(input_filenames[0]) - img.thumbnail(thumb_size) - offset = ( thumb_box[0] - inner_border - img.size[0] , - thumb_box[1] - inner_border - img.size[1] ) - output_image.paste(img, offset) - - # Image 1 - img = Image.open(input_filenames[1]) - img.thumbnail(thumb_size) - offset = ( thumb_box[0] + inner_border, - thumb_box[1] - inner_border - img.size[1] ) - output_image.paste(img, offset) - - # Image 2 - img = Image.open(input_filenames[2]) - img.thumbnail(thumb_size) - offset = ( thumb_box[0] - inner_border - img.size[0] , - thumb_box[1] + inner_border ) - output_image.paste(img, offset) - - # Image 3 - img = Image.open(input_filenames[3]) - img.thumbnail(thumb_size) - offset = ( thumb_box[0] + inner_border , - thumb_box[1] + inner_border ) - output_image.paste(img, offset) - - # Save assembled image - output_filename = self.pictures.get_next() - output_image.save(output_filename, "JPEG") - return output_filename - - def show_counter(self, seconds): - if self.camera.has_preview(): - tic = clock() - toc = clock() - tic - while toc < seconds: - self.display.clear() - self.camera.take_preview("/tmp/photobooth_preview.jpg") - self.display.show_picture("/tmp/photobooth_preview.jpg", flip=True) - self.display.show_message(str(seconds - int(toc))) - self.display.apply() - - # Limit progress to 1 "second" per preview (e.g., too slow on Raspi 1) - toc = min(toc + 1, clock() - tic) - else: - for i in range(seconds): - self.display.clear() - self.display.show_message(str(seconds - i)) - self.display.apply() - sleep(1) - - def take_picture(self): - """Implements the picture taking routine""" - # Disable lamp - self.gpio.set_output(self.lamp_channel, 0) - - # Show pose message - self.display.clear() - self.display.show_message("POSE!\n\nTaking four pictures..."); - self.display.apply() - sleep(2) - - # Extract display and image sizes - size = self.display.get_size() - outsize = (int(size[0]/2), int(size[1]/2)) - - # Take pictures - filenames = [i for i in range(4)] - for x in range(4): - # Countdown - self.show_counter(self.pose_time) - - # Try each picture up to 3 times - remaining_attempts = 3 - while remaining_attempts > 0: - remaining_attempts = remaining_attempts - 1 - - self.display.clear() - self.display.show_message("S M I L E !!!\n\n" + str(x+1) + " of 4") - self.display.apply() - - tic = clock() - - try: - filenames[x] = self.camera.take_picture("/tmp/photobooth_%02d.jpg" % x) - remaining_attempts = 0 - except CameraException as e: - # On recoverable errors: display message and retry - if e.recoverable: - if remaining_attempts > 0: - self.display.clear() - self.display.show_message(e.message) - self.display.apply() - sleep(5) - else: - raise CameraException("Giving up! Please start over!", False) - else: - raise e - - # Measure used time and sleep a second if too fast - toc = clock() - tic - if toc < 1.0: - sleep(1.0 - toc) - - # Show 'Wait' - self.display.clear() - self.display.show_message("Please wait!\n\nProcessing...") - self.display.apply() - - # Assemble them - outfile = self.assemble_pictures(filenames) - - # Show pictures for 10 seconds - self.display.clear() - self.display.show_picture(outfile, size, (0,0)) - self.display.apply() - sleep(self.display_time) - - # Reenable lamp - self.gpio.set_output(self.lamp_channel, 1) - - - - -################# -### Functions ### -################# - -def main(): - photobooth = Photobooth(display_size, picture_basename, image_size, pose_time, display_time, - gpio_trigger_channel, gpio_shutdown_channel, gpio_lamp_channel, - idle_slideshow, slideshow_display_time) - photobooth.run() - photobooth.teardown() - return 0 - -if __name__ == "__main__": - exit(main()) diff --git a/photobooth.sh b/photobooth.sh deleted file mode 100755 index d32b850..0000000 --- a/photobooth.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/bash - -PHOTOBOOTH_DIR=/home/pi/photobooth - -cd "${PHOTOBOOTH_DIR}" - -if [[ $1 == "set-time" ]]; then - sudo python set-time.py -fi - -sudo python photobooth.py >>photobooth.log 2>>photobooth.err - -cd - - diff --git a/set-time.py b/set-time.py deleted file mode 100755 index 19080d2..0000000 --- a/set-time.py +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env python -# Created by br _at_ re-web _dot_ eu, 2016 - -from gui import GUI_PyGame as GuiModule -from time import sleep - -import subprocess - -# Screen size -display_size = (1024, 600) - -# Button size -button_size = (70, 70) - -date_digits = ['D', 'D', 'M', 'M', 'Y', 'Y', 'Y', 'Y'] # DD-MM-YYYY -time_digits = ['H', 'H', 'M', 'M'] # HH-MM - -numpad = { '1': (100, 100), '2': (200, 100), '3': (300, 100), - '4': (100, 200), '5': (200, 200), '6': (300, 200), - '7': (100, 300), '8': (200, 300), '9': (300, 300), - '0': (200, 400) } - -################# -### Functions ### -################# - -def check_and_handle_events(display, digit): - r, e = display.check_for_event() - while r: - handle_event(e, digit) - r, e = display.check_for_event() - -def handle_event(event, digit, digits, numpad): - # mouseclick - if event.type == 2 and event.value[0] == 1: - print(event.value[1]) - for num, pos in numpad.items(): - if (event.value[1][0] > pos[0] and - event.value[1][0] < pos[0] + button_size[0] and - event.value[1][1] > pos[1] and - event.value[1][1] < pos[1] + button_size[1]): - digits[digit] = num - return True - return False - -def show_numpad(display, numpad, button_size): - for num, pos in numpad.items(): - display.show_button(num, pos, button_size) - -def show_digits(display, digits, button_size): - for i in range(len(digits)): - display.show_button(digits[i], (400 + i * (button_size[0] + 5), 200), button_size, outline=(0,0,0)) - -def main(): - display = GuiModule('set-time', display_size, hide_mouse=False) - - for digit in range(len(date_digits)): - display.clear() - - show_numpad(display, numpad, button_size) - display.show_button('Date:', (400, 100), outline=(0,0,0)) - show_digits(display, date_digits, button_size) - - display.apply() - - digit_done = False - while not digit_done: - r, e = display.check_for_event() - while r: - digit_done = handle_event(e, digit, date_digits, numpad) - r, e = display.check_for_event() - - for digit in range(len(time_digits)): - display.clear() - - show_numpad(display, numpad, button_size) - display.show_button('Time:', (400, 100), outline=(0,0,0)) - show_digits(display, time_digits, button_size) - - display.apply() - - digit_done = False - while not digit_done: - event = display.wait_for_event() - digit_done = handle_event(event, digit, time_digits, numpad) - - # YYYY-MM-DD HH:mm - date_str = ( date_digits[4] + date_digits[5] + date_digits[6] + date_digits[7] + '-' + - date_digits[2] + date_digits[3] + '-' + - date_digits[0] + date_digits[1] + ' ' + - time_digits[0] + time_digits[1] + ':' + time_digits[2] + time_digits[3] ) - - subprocess.check_call(['date', '-s', date_str]) - - display.teardown() - return 0 - -if __name__ == "__main__": - exit(main()) - \ No newline at end of file diff --git a/slideshow.py b/slideshow.py deleted file mode 100755 index 6b16a89..0000000 --- a/slideshow.py +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/env python -# Created by br@re-web.eu, 2015 - -from gui import GUI_PyGame as GuiModule - -import os -from datetime import datetime -import subprocess -import thread -from time import sleep - -##################### -### Configuration ### -##################### - -# Screen size -display_size = (1024, 768) - -# Directory for slideshow pictures -slideshow_directory = "slideshow/" - -# Source directory, can also be remote. -# Leave empty to disable sync -source_directory = "pi@photobooth:photobooth/" + datetime.now().strftime("%Y-%m-%d") - -# Display time (in seconds) for slideshow pictures -display_time = 3 - -# Waiting time (in seconds) between synchronizations -sync_time = 60 - -############### -### Classes ### -############### - -class Slideshow: - def __init__(self, display_size, display_time, directory, recursive=True): - self.directory = directory - self.recursive = recursive - self.filelist = [] - self.display = GuiModule("Slideshow", display_size) - self.display_time = display_time - self.next = 0 - - def scan(self): - filelist = [] - - if self.recursive: - # Recursively walk all entries in the directory - for root, dirnames, filenames in os.walk(self.directory, followlinks=True): - for filename in filenames: - filelist.append(os.path.join(root, filename)) - else: - # Add all entries in the directory - for item in os.listdir(self.directory): - filename = os.path.join(self.directory, item) - if os.path.isfile(filename): - filelist.append(filename) - - self.filelist = filelist - self.next = 0 - - def handle_event(self, event): - if event.type == 0: - self.teardown() - elif event.type == 1: - self.handle_keypress(event.value) - - def handle_keypress(self, key): - # Exit the application - if key == ord('q'): - self.teardown() - - def display_next(self, text=""): - if self.next >= len(self.filelist): - self.scan() - if not self.filelist: - self.display.clear() - if text: - self.display.show_message(text) - else: - self.display.show_message("No pictures available!") - self.display.apply() - else: - filename = self.filelist[self.next] - self.next += 1 - self.display.clear() - self.display.show_picture(filename) - if text: - self.display.show_message(text) - self.display.apply() - - def run(self): - while True: - self.display_next() - sleep(self.display_time) - r, e = self.display.check_for_event() - if r: - self.handle_event(e) - - def teardown(self): - self.display.teardown() - exit(0) - - -################# -### Functions ### -################# - -def sync_folders(source_directory, target_directory, wait_time): - sleep(5) - while True: - print("[" + datetime.now().strftime("%H:%M:%S") + "] Sync " - + source_directory + " --> " + target_directory) - try: - cmd = "rsync -rtu " + source_directory + " " + target_directory - output = subprocess.check_output(cmd, shell=True, stderr=subprocess.STDOUT) - except subprocess.CalledProcessError as e: - print("ERROR executing '" + e.cmd + "':\n" + e.output) - sleep(wait_time) - -def main(): - # Start a thread for syncing files - if len(source_directory) > 0: - thread.start_new_thread(sync_folders, (source_directory, slideshow_directory, sync_time) ) - - # Start the slideshow - slideshow = Slideshow(display_size, display_time, slideshow_directory, True) - slideshow.run() - - return 0 - -if __name__ == "__main__": - exit(main()) \ No newline at end of file diff --git a/transparent.msk b/transparent.msk deleted file mode 100644 index d893792..0000000 --- a/transparent.msk +++ /dev/null @@ -1,4 +0,0 @@ -#define transparent_width 8 -#define transparent_height 8 -static unsigned char transparent_bits[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; \ No newline at end of file diff --git a/transparent.xbm b/transparent.xbm deleted file mode 100644 index 94d7d29..0000000 --- a/transparent.xbm +++ /dev/null @@ -1,6 +0,0 @@ -#define transparent_width 8 -#define transparent_height 8 -#define transparent_x_hot 0 -#define transparent_y_hot 0 -static unsigned char transparent_bits[] = { - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; \ No newline at end of file