Compare commits

..

No commits in common. "5a460f7b5498ec307a3d5b3991a4fd4d77ac2369" and "9eb08d9d96ac9fd3a50b52b7dbdaa193e72fc583" have entirely different histories.

7 changed files with 302 additions and 347 deletions

3
.gitignore vendored
View File

@ -1,5 +1,2 @@
/.idea/
/venv/
/images/
/tmp?.jpg

View File

@ -1,27 +0,0 @@
BOARD = 1
HIGH = 1
LOW = 0
OUT = 1
IN = 0
FALLING = 0
RISING = 1
def setmode(x):
pass
def setwarnings(x):
pass
def setup(gpio, mode, initial=None):
pass
def output(gpio, state):
pass
def add_event_detect(gpio, edge, callback, bouncetime=None):
pass

Binary file not shown.

View File

@ -1,28 +0,0 @@
from PIL import Image
class Overlay(object):
def __init__(self):
self.alpha = 0
class PiCamera(object):
def __init__(self):
self.resolution = None
def start_preview(self, *args, **kwargs):
pass
def add_overlay(self, *args, **kwargs):
return Overlay()
def remove_overlay(self, *args, **kwargs):
pass
def capture(self, filename, format, *args, **kwargs):
print("FAKE: capture(%s, %s)" % (filename, format))
img = Image.new("RGB", self.resolution, (255, 255, 255))
img.save(filename, format)
def close(self, *args, **kwargs):
pass

Binary file not shown.

View File

@ -3,9 +3,9 @@
import json
import socket
UDP_IP = "255.255.255.255"
UDP_PORT = 32145
MESSAGE = {"subject": "Fotobox Broadcast", "port": 80}
UDP_IP = "255.255.255.255"
UDP_PORT = 32145
MESSAGE = {"subject": "Fotobox Broadcast", "port": 80}
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)

View File

@ -1,126 +1,125 @@
#!/usr/bin/python
import datetime
import imp
import inspect
import os
import sys
from math import floor
from shutil import copyfile
import sys, os, inspect
import pytz, datetime
from time import sleep
import pygame
from PIL import Image
from shutil import copyfile
from math import floor
import RPi.GPIO as GPIO
import picamera
import pygame
import random
import time
# ~ import server
try:
imp.find_module('RPi')
import RPi.GPIO as GPIO
except ImportError:
import FakeGPIO as GPIO
try:
imp.find_module('picamera')
import picamera
except ImportError:
import FakePicamera as picamera
__all__ = ["monotonic_time"]
import ctypes
CLOCK_MONOTONIC_RAW = 4 # see <linux/time.h>
CLOCK_MONOTONIC_RAW = 4 # see <linux/time.h>
class timespec(ctypes.Structure):
_fields_ = [
('tv_sec', ctypes.c_long),
('tv_nsec', ctypes.c_long)
]
_fields_ = [
('tv_sec', ctypes.c_long),
('tv_nsec', ctypes.c_long)
]
librt = ctypes.CDLL('librt.so.1', use_errno=True)
clock_gettime = librt.clock_gettime
clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)]
def monotonic_time():
t = timespec()
if clock_gettime(CLOCK_MONOTONIC_RAW, ctypes.pointer(t)) != 0:
errno_ = ctypes.get_errno()
raise OSError(errno_, os.strerror(errno_))
return t.tv_sec + t.tv_nsec * 1e-9
t = timespec()
if clock_gettime(CLOCK_MONOTONIC_RAW , ctypes.pointer(t)) != 0:
errno_ = ctypes.get_errno()
raise OSError(errno_, os.strerror(errno_))
return t.tv_sec + t.tv_nsec * 1e-9
os.chdir(os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))))
# CONFIGURATION
WIDTH = 800
HEIGHT = 480
FONTSIZE = 500
PIC_INTERVAL = 0.5
TEXT_INTERVAL = 0.5
TEXT_POS = (250, -40)
OVERLAY_ALPHA = 64
COLOR_BACK = pygame.Color(0, 0, 0)
COLOR_FLASH = pygame.Color(255, 255, 255)
GRAPHICS_DIR = "graphics"
IMAGE_DIR = "images/0-CURRENT"
COUNTDOWN = 3
SHOT_COUNT = 3
BORDER = 10
WIDTH = 800
HEIGHT = 480
FONTSIZE = 500
PIC_INTERVAL = 0.5
TEXT_INTERVAL = 0.5
TEXT_POS = (250, -40)
OVERLAY_ALPHA = 64
COLOR_BACK = pygame.Color(0, 0, 0)
COLOR_FLASH = pygame.Color(255, 255, 255)
GRAPHICS_DIR = "graphics"
IMAGE_DIR = "images/0-CURRENT"
COUNTDOWN = 3
SHOT_COUNT = 3
BORDER = 10
GPIO_LED_BORDER = 7
GPIO_SPOT_RIGHT = 35
GPIO_SPOT_LEFT = 37
GPIO_BUTTON_LED = 36
GPIO_BUTTON = 38
GPIO_LED_BORDER = 7
GPIO_SPOT_RIGHT = 35
GPIO_SPOT_LEFT = 37
GPIO_BUTTON_LED = 36
GPIO_BUTTON = 38
THUMB_WIDTH = int((800 - BORDER) / SHOT_COUNT - BORDER)
THUMB_HEIGHT = int(THUMB_WIDTH / 1.333)
IMAGES_ORIGINAL = os.path.join(IMAGE_DIR, "original")
IMAGES_TODO = os.path.join(IMAGE_DIR, "todo")
THUMB_WIDTH = int((800 - BORDER) / SHOT_COUNT - BORDER)
THUMB_HEIGHT = int(THUMB_WIDTH / 1.333)
IMAGES_ORIGINAL = os.path.join(IMAGE_DIR, "original")
IMAGES_TODO = os.path.join(IMAGE_DIR, "todo")
# global variables
spot_mode = 0
session_start = monotonic_time()
spot_mode = 0
session_start = monotonic_time()
# GPIO helpers
def led_border(state):
global GPIO_LED_BORDER
GPIO.output(GPIO_LED_BORDER, state)
global GPIO_LED_BORDER
GPIO.output(GPIO_LED_BORDER, state)
def set_spot_mode(new_mode):
global spot_mode
spot_mode = new_mode % 4
GPIO.output(GPIO_SPOT_LEFT, not (spot_mode & 1))
GPIO.output(GPIO_SPOT_RIGHT, not (spot_mode & 2))
global spot_mode
spot_mode = new_mode % 4
GPIO.output(GPIO_SPOT_LEFT, not (spot_mode & 1))
GPIO.output(GPIO_SPOT_RIGHT, not (spot_mode & 2))
def next_spot_mode():
global spot_mode
set_spot_mode(spot_mode + 1)
global spot_mode
set_spot_mode(spot_mode + 1)
# user interface
def button_press(gpio_id):
next_spot_mode()
next_spot_mode()
# INIT GPIO
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
GPIO.setup(GPIO_SPOT_RIGHT, GPIO.OUT, initial=GPIO.HIGH)
GPIO.setup(GPIO_SPOT_LEFT, GPIO.OUT, initial=GPIO.HIGH)
GPIO.setup(GPIO_LED_BORDER, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(GPIO_BUTTON_LED, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(GPIO_SPOT_RIGHT, GPIO.OUT, initial=GPIO.HIGH)
GPIO.setup(GPIO_SPOT_LEFT, GPIO.OUT, initial=GPIO.HIGH)
GPIO.setup(GPIO_LED_BORDER, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(GPIO_BUTTON_LED, GPIO.OUT, initial=GPIO.LOW)
GPIO.setup(GPIO_BUTTON, GPIO.IN)
GPIO.setup(GPIO_BUTTON, GPIO.IN)
GPIO.add_event_detect(GPIO_BUTTON, GPIO.FALLING, button_press, bouncetime=300)
led_border(False)
@ -137,24 +136,26 @@ led_border(True)
sleep(0.02)
led_border(False)
# INIT PYGAME
pygame.init()
pygame.mouse.set_visible(False)
screen = pygame.display.set_mode((WIDTH, HEIGHT))
screen = pygame.display.set_mode((WIDTH,HEIGHT))
# LOAD GRAPHICS
gfx = {}
def _load(name):
filename = "%s.png" % name
path = os.path.join(GRAPHICS_DIR, filename)
filename = "%s.png" % name
path = os.path.join(GRAPHICS_DIR, filename)
img = pygame.image.load(path)
rect = img.get_rect()
gfx[name] = (img, rect)
img = pygame.image.load(path)
rect = img.get_rect()
gfx[name] = (img, rect)
_load("begin")
_load("loading")
@ -165,249 +166,261 @@ _load("end_no")
_load("saved")
_load("canceled")
# LOAD COUNTDOWN OVERLAYS
img_cdn = []
pad_cdn = []
for i in range(0, COUNTDOWN):
filename = "%s.png" % (COUNTDOWN - i)
path = os.path.join(GRAPHICS_DIR, filename)
filename = "%s.png" % (COUNTDOWN - i)
path = os.path.join(GRAPHICS_DIR, filename)
img = Image.open(path)
pad = Image.new('RGB', (
((img.size[0] + 31) // 32) * 32,
((img.size[1] + 15) // 16) * 16,
))
pad.paste(img, (0, 0))
img_cdn.append(img)
pad_cdn.append(pad)
img = Image.open(path)
pad = Image.new('RGB', (
((img.size[0] + 31) // 32) * 32,
((img.size[1] + 15) // 16) * 16,
))
pad.paste(img, (0, 0))
img_cdn.append(img)
pad_cdn.append(pad)
# FUNCTIONS ========================================================================================
def waitForEvent():
pygame.event.clear()
while 1:
sleep(0.25)
pygame.event.clear()
while 1:
sleep(0.25)
events = pygame.event.get()
if len(events) > 0:
for event in events:
if event.type == pygame.QUIT:
sys.exit(0)
return events
events = pygame.event.get()
if len(events) > 0:
for event in events:
if event.type == pygame.QUIT:
sys.exit(0)
return events
def waitForTouch():
pos = (-1, -1)
while True:
events = waitForEvent()
for event in events:
if event.type == pygame.MOUSEMOTION:
pos = event.pos
elif event.type == pygame.MOUSEBUTTONUP:
return pos
pos = (-1, -1)
while True:
events = waitForEvent()
for event in events:
if event.type == pygame.MOUSEMOTION:
pos = event.pos
elif event.type == pygame.MOUSEBUTTONUP:
return pos
def maintainance():
screen.fill(COLOR_BACK)
screen.blit(maintain, maintain_rect)
pygame.display.flip()
screen.fill(COLOR_BACK)
screen.blit(maintain, maintain_rect)
pygame.display.flip()
# wait
pos = waitForTouch()
# wait
pos = waitForTouch()
def waitForBegin():
screen.fill(COLOR_BACK)
screen.blit(*gfx["begin"])
pygame.display.flip()
screen.fill(COLOR_BACK)
screen.blit(*gfx["begin"])
pygame.display.flip()
# wait
pos = waitForTouch()
if pos[0] > 720 and pos[1] > 400:
maintainance()
# wait
pos = waitForTouch()
if pos[0] > 720 and pos[1] > 400:
maintainance()
def countdown(camera, pad, img):
sleep(PIC_INTERVAL)
o = camera.add_overlay(pad.tobytes(), size=img.size)
o.alpha = OVERLAY_ALPHA
o.layer = 3
sleep(TEXT_INTERVAL)
camera.remove_overlay(o)
sleep(PIC_INTERVAL)
o = camera.add_overlay(pad.tostring(), size=img.size)
o.alpha = OVERLAY_ALPHA
o.layer = 3
sleep(TEXT_INTERVAL)
camera.remove_overlay(o)
def makePhotos():
# CLEAR SCREEN
screen.fill(COLOR_BACK)
pygame.display.update()
# CLEAR SCREEN
screen.fill(COLOR_BACK)
pygame.display.update()
# INIT CAMERA
camera = picamera.PiCamera()
camera.vflip = False
camera.hflip = True
camera.resolution = (2592, 1944)
camera.rotation = 90
camera.start_preview()
# INIT CAMERA
camera = picamera.PiCamera()
camera.vflip = False
camera.hflip = True
camera.resolution = (2592, 1944)
camera.rotation = 90
camera.start_preview()
# COUNTDOWN
led_border(True)
for i in range(0, COUNTDOWN):
countdown(camera, pad_cdn[i], img_cdn[i])
led_border(False)
# COUNTDOWN
led_border(True)
for i in range(0, COUNTDOWN):
countdown(camera, pad_cdn[i], img_cdn[i])
led_border(False)
# SHOTS
for i in range(0, SHOT_COUNT):
# SHOT!
sleep(PIC_INTERVAL)
led_border(True)
camera.capture("./tmp%s.jpg" % i, format='jpeg', quality=100, thumbnail=None)
led_border(False)
# SHOTS
for i in range(0, SHOT_COUNT):
# SHOT!
sleep(PIC_INTERVAL)
led_border(True)
camera.capture("./tmp%s.jpg" % i, format='jpeg', quality=100, thumbnail=None)
led_border(False)
# PAUSE
if i < SHOT_COUNT - 1:
screen.fill(COLOR_BACK)
pygame.display.update()
camera.start_preview()
sleep(TEXT_INTERVAL)
# PAUSE
if i < SHOT_COUNT - 1:
screen.fill(COLOR_BACK)
pygame.display.update()
camera.start_preview()
sleep(TEXT_INTERVAL)
# CLOSE CAMERA
camera.close()
# CLOSE CAMERA
camera.close()
def chooseImages():
# clear screen
screen.fill(COLOR_BACK)
screen.blit(*gfx["loading"])
pygame.display.update()
# clear screen
screen.fill(COLOR_BACK)
screen.blit(*gfx["loading"])
pygame.display.update()
# load images from disk
img_tmp = []
rect_tmp = []
choices = []
x = 12
for i in range(0, SHOT_COUNT):
img = pygame.image.load("tmp%s.jpg" % i)
img = pygame.transform.scale(img, (THUMB_WIDTH, THUMB_HEIGHT))
rect = img.get_rect()
rect.x = x
rect.y = 146
# load images from disk
img_tmp = []
rect_tmp = []
choices = []
x = 12
for i in range(0, SHOT_COUNT):
img = pygame.image.load("tmp%s.jpg" % i)
img = pygame.transform.scale(img, (THUMB_WIDTH, THUMB_HEIGHT))
rect = img.get_rect()
rect.x = x
rect.y = 146
img_tmp.append(img)
rect_tmp.append(rect)
choices.append(0)
img_tmp.append(img)
rect_tmp.append(rect)
choices.append(0)
x = x + THUMB_WIDTH + BORDER
x = x + THUMB_WIDTH + BORDER
save = False
cancel = False
any_choice = False
while not cancel and (not save or not any_choice):
# reset save (if nothing selected)
save = False
# draw background
screen.fill(COLOR_BACK)
if any_choice:
screen.blit(*gfx["end_yes"])
else:
screen.blit(*gfx["end_no"])
save = False
cancel = False
any_choice = False
while not cancel and (not save or not any_choice):
# reset save (if nothing selected)
save = False
# draw images
for i in range(0, SHOT_COUNT):
screen.blit(img_tmp[i], rect_tmp[i])
# draw background
screen.fill(COLOR_BACK)
if any_choice:
screen.blit(*gfx["end_yes"])
else:
screen.blit(*gfx["end_no"])
# draw choices
x = 12
for choice in choices:
if choice > 0:
(img, rect) = gfx["yes"]
else:
(img, rect) = gfx["no"]
# draw images
for i in range(0, SHOT_COUNT):
screen.blit(img_tmp[i], rect_tmp[i])
rect.x = x + (THUMB_WIDTH - rect.width) / 2
rect.y = 340
screen.blit(img, rect)
# draw choices
x = 12
for choice in choices:
if choice > 0:
(img, rect) = gfx["yes"]
else:
(img, rect) = gfx["no"]
x = x + THUMB_WIDTH + BORDER
rect.x = x + (THUMB_WIDTH - rect.width) / 2
rect.y = 340
screen.blit(img, rect)
# update display
pygame.display.flip()
x = x + THUMB_WIDTH + BORDER
# wait for new event (touch screen / mouse / keyboard)
pos = waitForTouch()
if pos[1] > 140:
# toggle image
i = int(floor((pos[0] - BORDER / 2) / (THUMB_WIDTH + BORDER)))
if i >= 0 and i < SHOT_COUNT:
choices[i] = (choices[i] + 1) % 2
# update display
pygame.display.flip()
elif pos[1] < 100:
# top menu buttons
if pos[0] > 0 and pos[0] < 266:
cancel = True
elif pos[0] > 533 and pos[0] < 800 and (choices[0] > 0 or choices[1] > 0 or choices[2] > 0):
save = True
# wait for new event (touch screen / mouse / keyboard)
pos = waitForTouch()
if pos[1] > 140:
# toggle image
i = int(floor((pos[0] - BORDER / 2) / (THUMB_WIDTH + BORDER)))
if i >= 0 and i < SHOT_COUNT:
choices[i] = (choices[i] + 1) % 2
any_choice = False
for choice in choices:
if choice > 0:
any_choice = True
break
elif pos[1] < 100:
# top menu buttons
if pos[0] > 0 and pos[0] < 266:
cancel = True
elif pos[0] > 533 and pos[0] < 800 and (choices[0] > 0 or choices[1] > 0 or choices[2] > 0):
save = True
any_choice = False
for choice in choices:
if choice > 0:
any_choice = True
break
return (choices, save)
return (choices, save)
def saveImages(choices):
local = datetime.datetime.now()
session_age = (monotonic_time() - session_start)
local = datetime.datetime.now()
session_age = (monotonic_time() - session_start)
try:
os.makedirs(IMAGES_ORIGINAL)
except OSError:
pass
try:
os.makedirs(IMAGES_ORIGINAL)
except OSError:
pass
try:
os.makedirs(IMAGES_TODO)
except OSError:
pass
try:
os.makedirs(IMAGES_TODO)
except OSError:
pass
print("saving images...")
for i in range(0, SHOT_COUNT):
if choices[i] > 0:
print(" saving image #%s" % i)
print("saving images...")
for i in range(0, SHOT_COUNT):
if choices[i] > 0:
print(" saving image #%s" % i)
filename = "%s-%s-session_age=%05d.jpg" % (local.strftime("%Y%m%dT%H:%M:%S.%f%z"), i, session_age)
filename = "%s-%s-session_age=%05d.jpg" % (local.strftime("%Y%m%dT%H:%M:%S.%f%z"), i, session_age)
path_tmp = "tmp%s.jpg" % i
path_original = os.path.join(IMAGES_ORIGINAL, filename)
path_todo = os.path.join(IMAGES_TODO, filename)
path_tmp = "tmp%s.jpg" % i
path_original = os.path.join(IMAGES_ORIGINAL, filename)
path_todo = os.path.join(IMAGES_TODO, filename)
os.rename(path_tmp, path_original)
copyfile(path_original, path_todo)
os.rename(path_tmp, path_original)
copyfile(path_original, path_todo)
try:
while 1:
waitForBegin()
while 1:
waitForBegin()
makePhotos()
(choices, save) = chooseImages()
if save:
saveImages(choices);
screen.fill(COLOR_BACK)
screen.blit(*gfx["saved"])
pygame.display.flip()
else:
screen.fill(COLOR_BACK)
screen.blit(*gfx["canceled"])
pygame.display.flip()
makePhotos()
(choices, save) = chooseImages()
if save:
saveImages(choices);
screen.fill(COLOR_BACK)
screen.blit(*gfx["saved"])
pygame.display.flip()
else:
screen.fill(COLOR_BACK)
screen.blit(*gfx["canceled"])
pygame.display.flip()
sleep(2)
sleep(2)
except KeyboardInterrupt:
print("")
print("")
finally:
led_border(False)
pygame.quit()
led_border(False)
pygame.quit()