#!/usr/bin/python import sys, os, inspect import pytz, datetime from time import sleep 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 __all__ = ["monotonic_time"] import ctypes CLOCK_MONOTONIC_RAW = 4 # see class timespec(ctypes.Structure): _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 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 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 session_start = monotonic_time() # CREATE DIRECTORIES try: os.makedirs(IMAGES_ORIGINAL) except OSError: pass try: os.makedirs(IMAGES_TODO) except OSError: pass # INIT GPIO GPIO.setmode(GPIO.BOARD) GPIO.setwarnings(False) GPIO.setup(7, GPIO.OUT) GPIO.output(7, GPIO.LOW) sleep(0.02) GPIO.output(7, GPIO.HIGH) sleep(0.02) GPIO.output(7, GPIO.LOW) sleep(0.02) GPIO.output(7, GPIO.HIGH) sleep(0.02) GPIO.output(7, GPIO.LOW) sleep(0.02) GPIO.output(7, GPIO.HIGH) sleep(0.02) GPIO.output(7, GPIO.LOW) # INIT PYGAME pygame.init() pygame.mouse.set_visible(False) screen = pygame.display.set_mode((WIDTH,HEIGHT)) # LOAD GRAPHICS gfx = {} def _load(name): filename = "%s.png" % name path = os.path.join(GRAPHICS_DIR, filename) img = pygame.image.load(path) rect = img.get_rect() gfx[name] = (img, rect) _load("begin") _load("loading") _load("yes") _load("no") _load("end_yes") _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) 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) 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 def maintainance(): screen.fill(COLOR_BACK) screen.blit(maintain, maintain_rect) pygame.display.flip() # wait pos = waitForTouch() def waitForBegin(): screen.fill(COLOR_BACK) screen.blit(*gfx["begin"]) pygame.display.flip() # 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.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() # INIT CAMERA camera = picamera.PiCamera() camera.vflip = False camera.hflip = True camera.resolution = (2592, 1944) camera.rotation = 90 camera.start_preview() # COUNTDOWN GPIO.output(7, GPIO.HIGH) for i in range(0, COUNTDOWN): countdown(camera, pad_cdn[i], img_cdn[i]) GPIO.output(7, GPIO.LOW) # SHOTS for i in range(0, SHOT_COUNT): # SHOT! sleep(PIC_INTERVAL) GPIO.output(7, GPIO.HIGH) camera.capture("./tmp%s.jpg" % i, format='jpeg', quality=100, thumbnail=None) GPIO.output(7, GPIO.LOW) # PAUSE if i < SHOT_COUNT - 1: screen.fill(COLOR_BACK) pygame.display.update() camera.start_preview() sleep(TEXT_INTERVAL) # CLOSE CAMERA camera.close() def chooseImages(): # 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 img_tmp.append(img) rect_tmp.append(rect) choices.append(0) 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"]) # draw images for i in range(0, SHOT_COUNT): screen.blit(img_tmp[i], rect_tmp[i]) # draw choices x = 12 for choice in choices: if choice > 0: (img, rect) = gfx["yes"] else: (img, rect) = gfx["no"] rect.x = x + (THUMB_WIDTH - rect.width) / 2 rect.y = 340 screen.blit(img, rect) x = x + THUMB_WIDTH + BORDER # update display pygame.display.flip() # 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 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) def saveImages(choices): local = datetime.datetime.now() session_age = (monotonic_time() - session_start) 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) 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) 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() sleep(2) pygame.quit()