Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
157 changes: 157 additions & 0 deletions RPiCameraPython/takeASnap.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<html>

<style>

.container {
position: relative;
text-align: center;
color: white;
}

.button{
height:200px;
width:200px;
}

.center {
text-align: center;
margin: auto;
width: 60%;
}

.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}


.img {
margin-bottom: 15px
border: 5px solid #555;
border-radius: 5px;
}

img {
border: 5px solid #555;
border-radius: 5px;
margin-bottom: 15px;
}

/* CSS */
.button-74 {
background-color: #fbeee0;
border: 2px solid #422800;
border-radius: 30px;
box-shadow: #422800 4px 4px 0 0;
color: #422800;
cursor: pointer;
display: inline-block;
font-weight: 600;
font-size: 18px;
padding: 0 18px;
line-height: 50px;
text-align: center;
text-decoration: none;
user-select: none;
-webkit-user-select: none;
touch-action: manipulation;
}

.button-74:hover {
background-color: #fff;
}

.button-74:active {
box-shadow: #422800 2px 2px 0 0;
transform: translate(2px, 2px);
}

@media (min-width: 768px) {
.button-74 {
min-width: 120px;
padding: 0 25px;
}
}
</style>
<head>
<title>picamera MJPEG Take a snap</title>
</head>
<body>
<div class="center">
<h1>Take snap</h1>
<div class="container">
<img id="camdisplay" src="stream.mjpg" width="640" height="480" />
<div class="centered"><h1 id="counter"></h1></div>
</div>
<br/>
<button id="snap" class="button-74">
TAKE A SNAP !!
</button>
</div>


<script>
function create_UUID(){
var dt = new Date().getTime();
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = (dt + Math.random()*16)%16 | 0;
dt = Math.floor(dt/16);
return (c=='x' ? r :(r&0x3|0x8)).toString(16);
});
return uuid;
}

function capturePic() {
// Creating Our XMLHttpRequest object
var xhr = new XMLHttpRequest();

// Making our connection
var url = '/snap';
xhr.open("GET", url, true);

// function execute after request is successful
xhr.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
let uuid = create_UUID()
console.log("Picture captured");
let camdisplay = document.getElementById("camdisplay");
camdisplay.setAttribute("src", "/lastSnappedImage?V=" + uuid);

setTimeout(function () {
camdisplay.setAttribute("src", "stream.mjpg");
}, 4000);
}
}
// Sending our request
xhr.send();
}

function snap() {
let count = 5
let x = setInterval(function() {

if (count == -1) {
clearInterval(x);
document.getElementById("counter").innerHTML = "";
}

else if (count == 0) {
document.getElementById("counter").innerHTML = "SNAP";
capturePic()
}
else {
document.getElementById("counter").innerHTML = count;
}
count--;
}, 1000)
}

let btn = document.getElementById("snap");
btn.addEventListener('click', event => {
snap();
});
</script>
</body>
</html>
94 changes: 94 additions & 0 deletions RPiCameraPython/takeASnap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import io
import picamera
import logging
import socketserver
from threading import Condition
from http import server
import shutil

with open('takeASnap.html', 'r') as file:
PAGE = file.read()

class StreamingOutput(object):
def __init__(self):
self.frame = None
self.buffer = io.BytesIO()
self.condition = Condition()

def write(self, buf):
if buf.startswith(b'\xff\xd8'):
# New frame, copy the existing buffer's content and notify all
# clients it's available
self.buffer.truncate()
with self.condition:
self.frame = self.buffer.getvalue()
self.condition.notify_all()
self.buffer.seek(0)
return self.buffer.write(buf)

class StreamingHandler(server.BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/':
self.send_response(301)
self.send_header('Location', '/index.html')
self.end_headers()
elif self.path == '/index.html':
content = PAGE.encode('utf-8')
self.send_response(200)
self.send_header('Content-Type', 'text/html')
self.send_header('Content-Length', len(content))
self.end_headers()
self.wfile.write(content)
elif self.path.startswith('/lastSnappedImage'):
self.send_response(200)
self.send_header('Content-type', 'image/jpeg')
self.end_headers()
with open('image.jpg', 'rb') as content:
shutil.copyfileobj(content, self.wfile)
elif self.path == '/snap':
print("SNAP !!!")
camera.capture('image.jpg')
self.send_response(200)
self.end_headers()
elif self.path == '/stream.mjpg':
self.send_response(200)
self.send_header('Age', 0)
self.send_header('Cache-Control', 'no-cache, private')
self.send_header('Pragma', 'no-cache')
self.send_header('Content-Type', 'multipart/x-mixed-replace; boundary=FRAME')
self.end_headers()
try:
while True:
with output.condition:
output.condition.wait()
frame = output.frame
self.wfile.write(b'--FRAME\r\n')
self.send_header('Content-Type', 'image/jpeg')
self.send_header('Content-Length', len(frame))
self.end_headers()
self.wfile.write(frame)
self.wfile.write(b'\r\n')
except Exception as e:
logging.warning(
'Removed streaming client %s: %s',
self.client_address, str(e))
else:
self.send_error(404)
self.end_headers()

class StreamingServer(socketserver.ThreadingMixIn, server.HTTPServer):
allow_reuse_address = True
daemon_threads = True

# 4 fps = 6 Mbps
#24 fps = 18 Mbps
with picamera.PiCamera(resolution='640x480', framerate=24) as camera:
#camera.rotation = 180
output = StreamingOutput()
camera.start_recording(output, format='mjpeg')
try:
address = ('', 8000)
server = StreamingServer(address, StreamingHandler)
server.serve_forever()
finally:
camera.stop_recording()