Photo booth
This commit is contained in:
32
photo-booth/README.md
Normal file
32
photo-booth/README.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# Photo booth web
|
||||
|
||||
This is a photo booth that posts the photos shot by the guests to the app.
|
||||
It shots a photo when the Enter or Space keys are pressed (I used one of these fluffy big USB Enter keys) and uploades it to the app on behalf of an existing user.
|
||||
|
||||
## Install
|
||||
|
||||
- Create an user that will post the photos adding a row in the user's table. Assign a token, any sufficiently strong string is ok.
|
||||
- Copy the current folder in the PC that will be used as Photo Booth
|
||||
- Copy config_example.js to config.js and edit it
|
||||
- Place your webservices url in BASEURL
|
||||
- Place the user's token in the config.
|
||||
- Configure the browser using the following indications:
|
||||
|
||||
```
|
||||
Use Firefox as browser. Go in about:config and set:
|
||||
browser.download.alwaysOpenPanel false // Prevents to open download list when taking a photo
|
||||
privacy.webrtc.legacyGlobalIndicator false // Hides camera overlay
|
||||
|
||||
When starting firefox in the photo booth totem, press F11 to make it full screen and leave only the Enter or Space key exposed
|
||||
If the download panel is shown anyway, right click on the download icon and deselect "Show panel when starting a download".
|
||||
If it appears already deselected, select and deselect it.
|
||||
```
|
||||
|
||||
|
||||
## Attributions
|
||||
|
||||
### Sounds
|
||||
|
||||
All creative commons:
|
||||
- Bike, Bell Ding, Single, 01-01.wav from InspectorJ (https://freesound.org/s/484344/)
|
||||
- Camera shutter.wav from jdaniel1999 (https://freesound.org/s/376205/)
|
||||
19
photo-booth/config_example.js
Normal file
19
photo-booth/config_example.js
Normal file
@@ -0,0 +1,19 @@
|
||||
// Configuration
|
||||
|
||||
const BASEURL = "https://mysite.com";
|
||||
const TOKEN = ""; // Photo booth user's token
|
||||
|
||||
const COUNTDOWN_FROM = 3;
|
||||
|
||||
|
||||
/*
|
||||
Browser configurations:
|
||||
|
||||
Use Firefox as browser. Go in about:config and set:
|
||||
browser.download.alwaysOpenPanel false // Prevents to open download list when taking a photo
|
||||
privacy.webrtc.legacyGlobalIndicator false // Hides camera overlay
|
||||
|
||||
When starting firefox in the photo booth totem, press F11 to make it full screen and leave only the Enter or Space key exposed
|
||||
If the download panel is shown anyway, right click on the download icon and deselect "Show panel when starting a download".
|
||||
If it appears already deselected, select and desenect it.
|
||||
*/
|
||||
BIN
photo-booth/ding.mp3
Normal file
BIN
photo-booth/ding.mp3
Normal file
Binary file not shown.
19
photo-booth/index.html
Normal file
19
photo-booth/index.html
Normal file
@@ -0,0 +1,19 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="it">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Photo booth</title>
|
||||
<link rel="stylesheet" href="style.css"/>
|
||||
<script type="text/javascript" src="config.js"></script>
|
||||
<script type="text/javascript" src="scripts/jquery-3.6.1.min.js"></script>
|
||||
<script type="text/javascript" src="scripts/script.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<video id="video" width="1920" height="1080" autoplay></video>
|
||||
<div id="canvas-container">
|
||||
<canvas id="canvas" width="3840" height="2160"></canvas>
|
||||
</div>
|
||||
<div id="flash"></div>
|
||||
<div id="countdown">3</div>
|
||||
</body>
|
||||
</html>
|
||||
2
photo-booth/scripts/jquery-3.6.1.min.js
vendored
Normal file
2
photo-booth/scripts/jquery-3.6.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
124
photo-booth/scripts/script.js
Normal file
124
photo-booth/scripts/script.js
Normal file
@@ -0,0 +1,124 @@
|
||||
// See https://davidwalsh.name/browser-camera
|
||||
|
||||
const shutterSound = new Audio('shutter.mp3');
|
||||
const countdownSound = new Audio('ding.mp3');
|
||||
let countingDown = false;
|
||||
|
||||
$(document).ready(function() {
|
||||
// Check if configuration is present
|
||||
try {
|
||||
BASEURL
|
||||
} catch (e) {
|
||||
alert("config.js not found!");
|
||||
return;
|
||||
}
|
||||
|
||||
// Shutter button press
|
||||
$(window).keydown(function(event){
|
||||
switch(event.keyCode) {
|
||||
case 13:
|
||||
case 32:
|
||||
onShutterButtonPressed();
|
||||
break
|
||||
default:
|
||||
console.log(`Ignored keypress ${event.keyCode}`)
|
||||
}
|
||||
});
|
||||
|
||||
// Get access to the camera!
|
||||
var video = $('#video')[0];
|
||||
if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
|
||||
// Not adding `{ audio: true }` since we only want video now
|
||||
navigator.mediaDevices.getUserMedia({ video: {
|
||||
width: 3840,
|
||||
height: 2160
|
||||
} }).then(function(stream) {
|
||||
//video.src = window.URL.createObjectURL(stream);
|
||||
video.srcObject = stream;
|
||||
video.play();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
function onShutterButtonPressed() {
|
||||
if (!countingDown)
|
||||
countdown(COUNTDOWN_FROM, takePhoto);
|
||||
}
|
||||
|
||||
function countdown(from, onCountdownElapsed) {
|
||||
countingDown = true;
|
||||
const countdownEl = $('#countdown');
|
||||
|
||||
if (from > 0) {
|
||||
if (from === COUNTDOWN_FROM)
|
||||
countdownEl.show();
|
||||
countdownSound.play();
|
||||
setTimeout(function() {countdown(from - 1, onCountdownElapsed)}, 1000);
|
||||
} else {
|
||||
countingDown = false;
|
||||
countdownEl.hide();
|
||||
onCountdownElapsed();
|
||||
}
|
||||
countdownEl.text(from);
|
||||
}
|
||||
|
||||
function takePhoto() {
|
||||
const canvas = $('#canvas');
|
||||
const canvasContainer = $('#canvas-container');
|
||||
const flash = $('#flash');
|
||||
const context = canvas[0].getContext('2d');
|
||||
context.drawImage(video, 0, 0, 3840, 2160);
|
||||
canvasContainer.show();
|
||||
flash.show();
|
||||
$('#video').addClass('blurred');
|
||||
shutterSound.play();
|
||||
uploadImage();
|
||||
|
||||
// Hide flash
|
||||
setTimeout(function() {
|
||||
flash.hide();
|
||||
}, 200)
|
||||
|
||||
// Hide canvas
|
||||
setTimeout(function() {
|
||||
canvasContainer.hide();
|
||||
$('#video').removeClass('blurred');
|
||||
}, 5000);
|
||||
}
|
||||
|
||||
function uploadImage() {
|
||||
document.querySelector("#canvas").toBlob(function(blob) {
|
||||
let file = new File([blob], 'photobooth.jpg', { type: 'image/jpeg' });
|
||||
let data = new FormData();
|
||||
data.append('image', file);
|
||||
|
||||
let request = new XMLHttpRequest();
|
||||
request.open('POST', `${BASEURL}/api/gallery_item/upload.php`);
|
||||
request.setRequestHeader('Authentication', TOKEN);
|
||||
request.addEventListener('load', function(e) {
|
||||
console.log(request.response);
|
||||
});
|
||||
request.send(data);
|
||||
saveLocalImage(file);
|
||||
}, 'image/jpeg', 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the image locally for backup
|
||||
*/
|
||||
function saveLocalImage(blob) {
|
||||
const fileName = `photobooth-${Date.now()}`
|
||||
if (typeof navigator.msSaveBlob == "function")
|
||||
return navigator.msSaveBlob(blob, fileName);
|
||||
|
||||
var saver = document.createElementNS("http://www.w3.org/1999/xhtml", "a");
|
||||
var blobURL = saver.href = URL.createObjectURL(blob),
|
||||
body = document.body;
|
||||
|
||||
saver.download = fileName;
|
||||
|
||||
body.appendChild(saver);
|
||||
saver.dispatchEvent(new MouseEvent("click"));
|
||||
body.removeChild(saver);
|
||||
URL.revokeObjectURL(blobURL);
|
||||
}
|
||||
BIN
photo-booth/shutter.mp3
Normal file
BIN
photo-booth/shutter.mp3
Normal file
Binary file not shown.
62
photo-booth/style.css
Normal file
62
photo-booth/style.css
Normal file
@@ -0,0 +1,62 @@
|
||||
body {
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
#video {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
position: absolute;
|
||||
cursor: none;
|
||||
}
|
||||
|
||||
.blurred {
|
||||
filter: blur(8px);
|
||||
}
|
||||
|
||||
#canvas-container {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
position: absolute;
|
||||
background-color: #000a;
|
||||
cursor: none;
|
||||
display: none;
|
||||
}
|
||||
|
||||
#canvas {
|
||||
width: 50vw;
|
||||
height: 50vh;
|
||||
position: relative;
|
||||
margin-left: 25vw;
|
||||
margin-top: 25vh;
|
||||
border: 100px solid white;
|
||||
left: -100px;
|
||||
top: -100px;
|
||||
cursor: none;
|
||||
}
|
||||
|
||||
#flash {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
position: absolute;
|
||||
display: none;
|
||||
background-color: white;
|
||||
cursor: none;
|
||||
}
|
||||
|
||||
#countdown {
|
||||
width: 600px;
|
||||
height: 600px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
margin-left: -300px;
|
||||
margin-top: -300px;
|
||||
font-size: 450px;
|
||||
text-align: center;
|
||||
font-family: sefif;
|
||||
color: white;
|
||||
background: #000a;
|
||||
border-radius: 100px;
|
||||
cursor: none;
|
||||
display: none;
|
||||
}
|
||||
Reference in New Issue
Block a user