Removed files from previous version

This commit is contained in:
Balthasar Reuter
2018-02-08 21:42:05 +01:00
parent e3c7515de2
commit 1da57c5bfc
9 changed files with 0 additions and 1110 deletions

133
camera.py
View File

@@ -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

View File

@@ -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)

245
gui.py
View File

@@ -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()

View File

@@ -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())

View File

@@ -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 -

View File

@@ -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())

View File

@@ -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())

View File

@@ -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};

View File

@@ -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};