344 lines
11 KiB
Python
Executable File
344 lines
11 KiB
Python
Executable File
# Raspberry Pi - Photo Booth
|
|
#
|
|
# Copyright (c) 2014, John Croucher - www.jcroucher.com
|
|
# All rights reserved.
|
|
#
|
|
# Redistribution and use in source and binary forms, with or without modification,
|
|
# are permitted provided that the following conditions are met:
|
|
#
|
|
# 1. Redistributions of source code must retain the above copyright notice, this
|
|
# list of conditions and the following disclaimer.
|
|
#
|
|
# 2. Redistributions in binary form must reproduce the above copyright notice, this
|
|
# list of conditions and the following disclaimer in the documentation and/or other
|
|
# materials provided with the distribution.
|
|
#
|
|
# 3. Neither the name of the copyright holder nor the names of its contributors may
|
|
# be used to endorse or promote products derived from this software without specific
|
|
# prior written permission.
|
|
#
|
|
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
# BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
|
# IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
|
# THE POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
|
|
import RPi.GPIO as GPIO
|
|
GPIO.setmode(GPIO.BOARD)
|
|
import tweepy
|
|
import time
|
|
from threading import Thread
|
|
from subprocess import call
|
|
from datetime import datetime
|
|
import picamera
|
|
import PIL
|
|
from PIL import Image
|
|
#import cups
|
|
import os
|
|
import sys
|
|
import pygame
|
|
import random
|
|
import requests
|
|
import urllib
|
|
buttonled = 7
|
|
flashled = 22
|
|
button = 18
|
|
|
|
slideshowRunning = True
|
|
basewidth = 177 # Used for merging the photos onto one
|
|
printPhoto = False
|
|
TweetPhoto = True
|
|
Combine = True
|
|
imgPath = '/home/pi/BoothPi/.images/tmp'
|
|
|
|
# Light big light
|
|
GPIO.setup(buttonled, GPIO.OUT) ## Setup GPIO Pin 7 to OUT
|
|
GPIO.output(buttonled, 1) ## Turn on GPIO pin 7
|
|
|
|
# Push button for starting the photo sequence
|
|
GPIO.setup(button, GPIO.IN, pull_up_down=GPIO.PUD_UP)
|
|
|
|
# Display surface
|
|
pygame.init()
|
|
|
|
pygame.mouse.set_visible(0)
|
|
|
|
w = pygame.display.Info().current_w
|
|
h = pygame.display.Info().current_h
|
|
|
|
screenSize = (w, h)
|
|
|
|
screen = pygame.display.set_mode(screenSize, pygame.FULLSCREEN) # Full screen the display with no window
|
|
|
|
|
|
# Used for loading a random photo for the slideshow
|
|
def random_file(dir):
|
|
files = [os.path.join(path, filename)
|
|
for path, dirs, files in os.walk(dir)
|
|
for filename in files]
|
|
|
|
return random.choice(files)
|
|
|
|
|
|
def displayImage(file):
|
|
screen.fill((0,0,0))
|
|
|
|
img = pygame.image.load(file)
|
|
img = pygame.transform.scale(img,(w,h)) # Make the image full screen
|
|
screen.blit(img,(0,0))
|
|
pygame.display.flip() # update the display
|
|
|
|
|
|
# Display a random image
|
|
def slideshow():
|
|
while True:
|
|
|
|
if slideshowRunning == True:
|
|
|
|
checkEvents()
|
|
|
|
randomFile = random_file('/home/pi/BoothPi/.images')
|
|
|
|
displayImage(randomFile)
|
|
|
|
time.sleep(10) # pause
|
|
|
|
# Handle events like keypress
|
|
def checkEvents():
|
|
for event in pygame.event.get():
|
|
# Shutdown the application if quit event or escape key is pressed
|
|
if event.type == pygame.QUIT or ( event.type is pygame.KEYDOWN and event.key == pygame.K_ESCAPE ):
|
|
slideshowRunning = False
|
|
pygame.quit()
|
|
sys.exit()
|
|
|
|
if event.type is pygame.KEYDOWN and event.key == pygame.K_f: # Switch the display mode between full screen and windowed
|
|
if screen.get_flags() & pygame.FULLSCREEN:
|
|
pygame.display.set_mode(screenSize)
|
|
else:
|
|
pygame.display.set_mode(screenSize,pygame.FULLSCREEN)
|
|
|
|
# On screen text message
|
|
def displayStatus(status):
|
|
screen.fill((0,0,0))
|
|
|
|
font = pygame.font.SysFont("monospace",92)
|
|
text = font.render(status,True,(255,255,255))
|
|
|
|
# Display in the center of the screen
|
|
textrect = text.get_rect()
|
|
textrect.centerx = screen.get_rect().centerx
|
|
textrect.centery = screen.get_rect().centery
|
|
|
|
screen.blit(text,textrect)
|
|
|
|
pygame.display.flip() # update the display
|
|
|
|
|
|
# Merge all photos onto one ready for printing
|
|
def combineImages():
|
|
if Combine == True:
|
|
displayStatus('Saving')
|
|
|
|
# Do the merging
|
|
blankImage = Image.open('blank.jpg')
|
|
|
|
image1 = Image.open(imgPath + '/image1.jpg')
|
|
image1 = image1.resize((640,480))
|
|
blankImage.paste(image1, (0,0))
|
|
displayStatus('25%')
|
|
|
|
image2 = Image.open(imgPath + '/image2.jpg')
|
|
image2 = image2.resize((640,480))
|
|
blankImage.paste(image2, (0,480))
|
|
displayStatus('50%')
|
|
|
|
image3 = Image.open(imgPath + '/image3.jpg')
|
|
image3 = image3.resize((640,480))
|
|
blankImage.paste(image3, (640,0))
|
|
displayStatus('75%')
|
|
|
|
image4 = Image.open(imgPath + '/image4.jpg')
|
|
image4 = image4.resize((640,600))
|
|
blankImage.paste(image4, (640,480))
|
|
displayStatus('100%')
|
|
|
|
blankImage.save(imgPath + '/combined.jpg', 'JPEG', quality=80)
|
|
displayStatus('Saved')
|
|
|
|
# Check net
|
|
def CheckNet():
|
|
try :
|
|
stri = "https://www.google.com"
|
|
data = urllib.urlopen(stri)
|
|
Tweet()
|
|
except:
|
|
displayStatus('Offline')
|
|
time.sleep(3) # pause
|
|
|
|
|
|
# Upload to Twitter
|
|
def Tweet():
|
|
if Combine == True:
|
|
if TweetPhoto == True:
|
|
displayStatus('Tweeting')
|
|
|
|
# Consumer keys and access tokens, used for OAuth
|
|
consumer_key = 'DVW3lqng3wY6hE77L7HV3Pq6o'
|
|
consumer_secret = 'o8hOsaAGuDkoHyH8CjBrhhAYidf8KsyubAVhad6bAZDlP0nQ6U'
|
|
access_token = '2867471873-HPqS3vtqHUOJHnWskkZK4ofZNWM7laef6L1LTWa'
|
|
access_token_secret = 'rZbxlDLqlgGuHZRXSH2V2rMRzWJLAIXWSbxorpZrFgVDX'
|
|
|
|
# OAuth process, using the keys and tokens
|
|
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
|
|
auth.set_access_token(access_token, access_token_secret)
|
|
|
|
# Creation of the actual interface, using authentication
|
|
api = tweepy.API(auth)
|
|
|
|
# Send the tweet with photo
|
|
photo_path = imgPath + '/combined.jpg'
|
|
status = 'Photo Tweet from HudgellBooth: ' + i.strftime('%Y/%m/%d %H:%M:%S')
|
|
api.update_with_media(photo_path, status=status)
|
|
displayStatus('Complete')
|
|
|
|
if Combine == False:
|
|
if TweetPhoto == True:
|
|
displayStatus('Tweeting')
|
|
|
|
# Consumer keys and access tokens, used for OAuth
|
|
consumer_key = 'DVW3lqng3wY6hE77L7HV3Pq6o'
|
|
consumer_secret = 'o8hOsaAGuDkoHyH8CjBrhhAYidf8KsyubAVhad6bAZDlP0nQ6U'
|
|
access_token = '2867471873-HPqS3vtqHUOJHnWskkZK4ofZNWM7laef6L1LTWa'
|
|
access_token_secret = 'rZbxlDLqlgGuHZRXSH2V2rMRzWJLAIXWSbxorpZrFgVDX'
|
|
|
|
# OAuth process, using the keys and tokens
|
|
auth = tweepy.OAuthHandler(consumer_key, consumer_secret)
|
|
auth.set_access_token(access_token, access_token_secret)
|
|
|
|
# Creation of the actual interface, using authentication
|
|
api = tweepy.API(auth)
|
|
|
|
# Send the tweet with photo 1
|
|
displayStatus('25%')
|
|
photo_path = imgPath + '/image1.jpg'
|
|
status = 'Photo Tweet from HudgellBooth: ' + i.strftime('%Y/%m/%d %H:%M:%S')
|
|
api.update_with_media(photo_path, status=status)
|
|
|
|
# Send the tweet with photo 2
|
|
displayStatus('50%')
|
|
photo_path = imgPath + '/image2.jpg'
|
|
status = 'Photo Tweet from HudgellBooth: ' + i.strftime('%Y/%m/%d %H:%M:%S')
|
|
api.update_with_media(photo_path, status=status)
|
|
|
|
# Send the tweet with photo 3
|
|
displayStatus('75%')
|
|
photo_path = imgPath + '/image3.jpg'
|
|
status = 'Photo Tweet from HudgellBooth: ' + i.strftime('%Y/%m/%d %H:%M:%S')
|
|
api.update_with_media(photo_path, status=status)
|
|
|
|
# Send the tweet with photo 4
|
|
displayStatus('100%')
|
|
photo_path = imgPath + '/image4.jpg'
|
|
status = 'Photo Tweet from HudgellBooth: ' + i.strftime('%Y/%m/%d %H:%M:%S')
|
|
api.update_with_media(photo_path, status=status)
|
|
displayStatus('Complete')
|
|
|
|
# Print the photo
|
|
def printPhoto():
|
|
if printPhoto == True:
|
|
displayStatus('Printing')
|
|
|
|
conn = cups.Connection()
|
|
printers = conn.getPrinters()
|
|
printer_name = printers.keys()[0]
|
|
conn.printFile(printer_name, imgPath + '/combined.jpg',"TITLE",{})
|
|
|
|
time.sleep(2)
|
|
|
|
# Combine Preview
|
|
def combinePre():
|
|
if Combine == True:
|
|
displayImage( imgPath + '/combined.jpg' ) # Display a preview of the combined image
|
|
|
|
|
|
# Thread for the slideshow
|
|
t = Thread(target=slideshow)
|
|
t.start()
|
|
|
|
with picamera.PiCamera() as camera:
|
|
|
|
while True:
|
|
checkEvents() # Needed to check for keypresses and close signals
|
|
|
|
# Putton press to start the photo sequence
|
|
input_state = GPIO.input(button)
|
|
if input_state == False:
|
|
|
|
GPIO.output(buttonled, 0) ## Turn off GPIO pin 7
|
|
|
|
# Stop the slideshow
|
|
slideshowRunning = False
|
|
displayStatus('')
|
|
|
|
# Start the camera preview
|
|
camera.hflip = False
|
|
camera.vflip = False
|
|
|
|
camera.start_preview()
|
|
|
|
# Make the destination path for the photos
|
|
if not os.path.exists(imgPath):
|
|
os.mkdir(imgPath)
|
|
|
|
# Loop through the 4 photo taking sequences
|
|
GPIO.setup(flashled, GPIO.OUT) ## Setup GPIO Pin 22 to OUT
|
|
GPIO.output(flashled, 1) ## Turn on GPIO pin 22
|
|
i = datetime.now() #take time and date for filename
|
|
now = i.strftime('%Y%m%d-%H%M%S')
|
|
|
|
for pNum in range (1,5):
|
|
camera.annotate_text = 'Photo ' + str(pNum) + ' of 4'
|
|
time.sleep(1)
|
|
|
|
for countDown in range (3,0,-1):
|
|
camera.annotate_text = str(countDown)
|
|
time.sleep(1)
|
|
|
|
camera.annotate_text = ''
|
|
#camera.resolution = (2560, 1920)
|
|
camera.resolution = (1280, 960)
|
|
os.system('omxplayer CSC.mp3 &')
|
|
camera.capture ( imgPath + '/image' + str(pNum) + '.jpg')
|
|
time.sleep(3)
|
|
|
|
# Stop the camera preview so we can return to the pygame surface
|
|
GPIO.output(flashled, 0) ## Turn on GPIO pin 7
|
|
camera.stop_preview()
|
|
|
|
combineImages()
|
|
|
|
CheckNet()
|
|
|
|
printPhoto()
|
|
|
|
combinePre()
|
|
|
|
time.sleep(5)
|
|
|
|
# Move the temp files to a new dir based on the current timestamp so they can be retrieved later
|
|
os.rename(imgPath, '/home/pi/BoothPi/.images/' + str(int(time.time())))
|
|
|
|
GPIO.output(buttonled, 1) ## Turn on GPIO pin 7
|
|
|
|
# Restart the slideshow
|
|
slideshowRunning = True
|
|
|