From b8e7ac2c5565add1c1fadb6177cd7613b6c9f2e5 Mon Sep 17 00:00:00 2001 From: Balthasar Reuter Date: Thu, 15 Sep 2016 00:14:55 +0200 Subject: [PATCH] Option added to show a slideshow of taken pictures when idle --- gui.py | 22 +++++++++++------ photobooth.py | 68 +++++++++++++++++++++++++++++++++++++++------------ slideshow.py | 41 +++++++++++++++++++------------ 3 files changed, 93 insertions(+), 38 deletions(-) diff --git a/gui.py b/gui.py index 2bdf277..07ca85e 100644 --- a/gui.py +++ b/gui.py @@ -78,12 +78,12 @@ class GUI_PyGame: surface = pygame.transform.flip(surface, True, False) self.surface_list.append((surface, offset)) - def show_message(self, msg, color=(245,245,245), bg=(0,0,0), transparency=True): + 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) + rendered_text = self.render_text(wrapped_text, text_height, 1, 1, font, color, bg, transparency, outline) self.surface_list.append((rendered_text, (0,0))) @@ -137,7 +137,7 @@ class GUI_PyGame: return final_lines, accumulated_height - def render_text(self, text, text_height, valign, halign, font, color, bg, transparency): + def render_text(self, text, text_height, valign, halign, font, color, bg, transparency, outline): # Determine vertical position if valign == 0: # top aligned voffset = 0 @@ -155,16 +155,24 @@ class GUI_PyGame: # Blit one line after another accumulated_height = 0 for line in text: - tempsurface = font.render(line, 1, color) + 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] - tempsurface.get_width()) / 2 + hoffset = (self.size[0] - maintext.get_width()) / 2 elif halign == 2: # right aligned - hoffset = rect.width - tempsurface.get_width() + hoffset = rect.width - maintext.get_width() else: raise GuiException("Invalid halign argument: " + str(justification)) - surface.blit(tempsurface, (hoffset, voffset + accumulated_height)) + 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 diff --git a/photobooth.py b/photobooth.py index 5d55bca..bfba0ca 100755 --- a/photobooth.py +++ b/photobooth.py @@ -10,8 +10,9 @@ 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_cv as CameraModule from camera import CameraException, Camera_gPhoto as CameraModule +from slideshow import Slideshow from events import Rpi_GPIO as GPIO ##################### @@ -42,9 +43,15 @@ gpio_lamp_channel = 4 # pin 7 in all Raspi-Versions # Waiting time in seconds for posing pose_time = 5 -# Display time for taken pictures +# 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 ### ############### @@ -105,7 +112,7 @@ class Photobooth: """ def __init__(self, display_size, picture_basename, picture_size, pose_time, display_time, - trigger_channel, shutdown_channel, lamp_channel): + 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) @@ -118,6 +125,12 @@ class Photobooth: 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) @@ -132,21 +145,38 @@ class Photobooth: 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) - 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) + # Select idle screen type + if self.idle_slideshow: + self._run_slideshow() + else: + self._run_plain() # Catch exceptions and display message except CameraException as e: @@ -158,6 +188,12 @@ class Photobooth: 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) @@ -282,14 +318,13 @@ class Photobooth: def show_counter(self, seconds): if self.camera.has_preview(): - tic, toc = clock(), 0 - while toc < self.pose_time: + tic = clock() + while clock() - tic < 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(clock() - tic))) self.display.apply() - toc = clock() - tic else: for i in range(seconds): self.display.clear() @@ -376,7 +411,8 @@ class Photobooth: def main(): photobooth = Photobooth(display_size, picture_basename, image_size, pose_time, display_time, - gpio_trigger_channel, gpio_shutdown_channel, gpio_lamp_channel) + gpio_trigger_channel, gpio_shutdown_channel, gpio_lamp_channel, + idle_slideshow, slideshow_display_time) photobooth.run() photobooth.teardown() return 0 diff --git a/slideshow.py b/slideshow.py index 9dee8dd..6b16a89 100755 --- a/slideshow.py +++ b/slideshow.py @@ -40,6 +40,7 @@ class Slideshow: self.filelist = [] self.display = GuiModule("Slideshow", display_size) self.display_time = display_time + self.next = 0 def scan(self): filelist = [] @@ -57,6 +58,7 @@ class Slideshow: filelist.append(filename) self.filelist = filelist + self.next = 0 def handle_event(self, event): if event.type == 0: @@ -69,23 +71,32 @@ class Slideshow: 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.scan() - if len(self.filelist) == 0: - self.display.clear() - self.display.show_message("No pictures available!") - self.display.apply() - sleep(10) - else: - for filename in self.filelist: - self.display.clear() - self.display.show_picture(filename) - self.display.apply() - sleep(self.display_time) - r, e = self.display.check_for_event() - if r: - self.handle_event(e) + 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()