Compare commits

..

No commits in common. "39513b8f36fb62273c989dddbfaf4f7a1f420308" and "9aa91985c9fee40737330e25dc968ff17780308b" have entirely different histories.

8 changed files with 148 additions and 5805 deletions

0
server/entrypoint.sh → entrypoint.sh Executable file → Normal file
View File

View File

@ -3,33 +3,22 @@
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=Edge" />
<meta name="mobile-web-app-capable" content="yes">
<title>Camera to laser roxxx!! </title>
<meta name="description" content="The" />
<style>
video,canvas { border: 1px solid #ccc; display: block; margin: auto; }
#canvas { display: block; }
video { border: 1px solid #ccc; display: block; margin: 0 0 20px 0; }
#canvas { margin-top: 20px; border: 1px solid #ccc; display: block; }
span.ui-slider-handle.ui-corner-all.ui-state-default { background: dodgerblue;}
canvas#simuCanvas {background: #333;}
div.select {
display: inline-block;
margin: 0 0 1em 0;
}
p.small {
font-size: 0.7em;
}
label {
width: 12em;
display: inline-block;
}
</style>
<link rel="stylesheet" type="text/css" href="css/bootstrap/css/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="js/jquery-ui/jquery-ui.css" />
<link rel="stylesheet" type="text/css" href="js/cropper/cropper.min.css" />
<script src="js/jquery-3.5.1.min.js"></script>
<script src="js/cropper/cropper.min.js"></script>
<script src="js/jquery-ui/jquery-ui.js"></script>
<script src="js/canvas.js"></script>
</head>
<body>
@ -37,47 +26,42 @@
<div class="container-fluid container-md">
<div class="row">
<div class="col-sm col-6">
<video id="video" class="video_sized" autoplay></video>
<div class="col-sm">
<div class="select">
<label for="videoSource">Video source: </label>
<select id="videoSource">
</select>
</div>
<h1 class="text-primary">Send shots to the laser!</h1>
</div>
</div>
<div class="row">
<div class="col-sm">
<video id="video" autoplay></video>
</div>
<div class="col-sm">
<h1 class="text-primary">Convert your photos to laser images!</h1>
<p class="lead">Once you allow the browser to use your camera, you can start creating something new by taking a snapshot. </p>
<p class="lead">If you're happy with the result, send it to see it converted to a laser-ready image! </p>
<div class="select">
<label for="videoSource">Change camera </label><select id="videoSource" class="custom-select"></select>
</div>
<button class="snap btn btn-lg btn-primary">Take a snap</button>
<button class="snap btn btn-lg btn-primary">Take a picture!</button>
<p class="lead">By allowing the use of your camera, you will be able to take snapshots, convert them to black and white images before sending them to the laser server. How cool is that?!</p>
</div>
</div>
<div class="row" id="result">
<div class="col-sm col-6">
<div class="video_sized">
<canvas id="canvas" class="video_sized"></canvas>
</div>
<div class="col-sm">
<canvas id="canvas" width="640" height="480"></canvas>
</div>
<div class="col-sm">
<h1 class="text-primary">Are you satisfied with the contrast? </h3>
<p>Before sending your snap, change the contrast using the slider to reach the effect you desire.</p><br/>
<h3 class="snap btn btn-lg btn-primary">Not satisfied of the contrast? </h3>
<br/>
<div id="slider"></div>
<br/>
<div class="float-left">
<button type="button" class="btn btn-secondary contrast" rel="-5">
<span class="badge badge-light">+</span> white
</button>
</div>
<div class="float-right">
<button type="button" class="btn btn-secondary contrast" rel="5">
<span class="badge badge-light">+</span> black
</button>
</div><br>
<div class="float-left">white ++</div>
<div class="float-right">++ dark</div><br>
<br/>
<h3>Ready to send? </h3>
<p >If some text is visible on the image, type it before pushing the Send button.</p>
<h3>Satisfied? </h3>
<p class="lead">Type the text visible on your image (if any) and push Send.</p>
<div class="form-group">
<input id="text" type="text" class="form-control form-control-lg" placeholder="Type text here"/>
<button id="send" class="form-control form-control-lg btn btn-lg btn-success btn-block">Send</button>
<button id="send" class="form-control form-control-lg btn btn-lg btn-warning btn-block">Send</button>
</div>
<div id="messages">
@ -85,13 +69,11 @@
</div>
</div>
<div class="row" id="preview">
<div class="col-sm col-6">
<canvas id="simuCanvas" class="video_sized"></canvas>
<div class="col-sm">
<canvas id="simuCanvas" width="640" height="480"></canvas>
</div>
<div class="col-sm" >
<h1 class="text-primary">Preview your creation</h1>
<p>Now that your creation have been sent, you can check what they will look like on lasers using these links, sorted by oldest snaps last.</p>
<h3>Your images</h3>
<div id="imageList"></div>
</div>
</div>
@ -101,11 +83,5 @@
</main>
<script src="js/jquery-3.5.1.min.js"></script>
<script src="js/cropper/cropper.min.js"></script>
<script src="js/jquery-ui/jquery-ui.js"></script>
<script src="js/canvas.js"></script>
<script src="js/adapter-latest.js"></script>
<script src="js/camera.js" async></script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -1,74 +0,0 @@
/*
* Copyright (c) 2015 The WebRTC project authors. All Rights Reserved.
*
* Use of this source code is governed by a BSD-style license
* that can be found in the LICENSE file in the root of the source
* tree.
*/
'use strict';
const videoElement = document.querySelector('video');
const videoSelect = document.querySelector('select#videoSource');
const resizableElements = document.querySelectorAll(".video_sized")
const selectors = [ videoSelect];
function gotDevices(deviceInfos) {
// Handles being called several times to update labels. Preserve values.
const values = selectors.map(select => select.value);
selectors.forEach(select => {
while (select.firstChild) {
select.removeChild(select.firstChild);
}
});
for (let i = 0; i !== deviceInfos.length; ++i) {
const deviceInfo = deviceInfos[i];
const option = document.createElement('option');
option.value = deviceInfo.deviceId;
if (deviceInfo.kind === 'videoinput') {
option.text = deviceInfo.label || `camera ${videoSelect.length + 1}`;
videoSelect.appendChild(option);
}
}
selectors.forEach((select, selectorIndex) => {
if (Array.prototype.slice.call(select.childNodes).some(n => n.value === values[selectorIndex])) {
select.value = values[selectorIndex];
}
});
}
navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);
function gotStream(stream) {
window.stream = stream; // make stream available to console
videoElement.srcObject = stream;
let track = stream.getTracks()[0]
let settings = track.getSettings()
resizableElements.forEach( el => { el.width = settings.width; el.height = settings.height; } )
// Refresh button list in case labels have become available
return navigator.mediaDevices.enumerateDevices();
}
function handleError(error) {
console.log('navigator.MediaDevices.getUserMedia error: ', error.message, error.name);
}
function start() {
if (window.stream) {
window.stream.getTracks().forEach(track => {
track.stop();
});
}
const videoSource = videoSelect.value;
const constraints = {
video: {deviceId: videoSource ? {exact: videoSource} : undefined}
};
navigator.mediaDevices.getUserMedia(constraints).then(gotStream).then(gotDevices).catch(handleError);
}
videoSelect.onchange = start;
start();

View File

@ -5,11 +5,8 @@ $(document).ready(function(){
var url = document.location.origin
var cropper = null
var snap = null
Cropper.setDefaults({
viewMode: 1,
autoCropArea: 0.9
})
var width;
var height;
// Grab elements, create settings, etc.
var canvas = document.getElementById('canvas');
@ -25,28 +22,114 @@ $(document).ready(function(){
**/
function doSnap(){
cropper && cropper.destroy()
let width = video.width
let height = video.height
context.drawImage(video, 0, 0, width, height);
snap = context.createImageData(width, height);
snap.data.set( context.getImageData(0, 0, width, height).data )
binary(context)
$("#result").show()
// Animation removed: it was causing problems with the send button. Fix.
//$('html, body').animate({scrollTop: $("#result").offset().top}, 2000);
cropper = new Cropper(canvas);
cropper = new Cropper(canvas,{
viewMode: 3,
autoCropArea: 1
});
}
function doContrast(){
let cropperData = {}
if( cropper ){
cropperData = cropper.getData()
cropper.destroy()
}
cropper && cropper.destroy()
context.putImageData(snap,0,0)
binary(context)
cropper = new Cropper(canvas);
setTimeout( () => { cropper.setData(cropperData) ; },30)
cropper = new Cropper(canvas,{
viewMode: 3,
autoCropArea: 1
});
}
// https://raw.githubusercontent.com/samdutton/simpl/gh-pages/getusermedia/sources/js/main.js
var videoElement = document.querySelector('video');
var videoSelect = document.querySelector('select#videoSource');
videoSelect.onchange = getStream;
getStream().then(getDevices).then(gotDevices);
function getDevices() {
// AFAICT in Safari this only gets default devices until gUM is called :/
return navigator.mediaDevices.enumerateDevices();
}
function gotDevices(deviceInfos) {
window.deviceInfos = deviceInfos; // make available to console
for (const deviceInfo of deviceInfos) {
const option = document.createElement('option');
option.value = deviceInfo.deviceId;
option.text = deviceInfo.label || `Camera ${videoSelect.length + 1}`;
videoSelect.appendChild(option);
}
}
function getStream() {
if (window.stream) {
window.stream.getTracks().forEach(track => {
track.stop();
});
}
const videoSource = videoSelect.value;
const constraints = {
video: {deviceId: videoSource ? {exact: videoSource} : undefined}
};
return navigator.mediaDevices.getUserMedia(constraints).
then(gotStream).catch(handleError);
}
function gotStream(stream) {
window.stream = stream; // make stream available to console
videoSelect.selectedIndex = [...videoSelect.options].
findIndex(option => option.text === stream.getVideoTracks()[0].label);
videoElement.srcObject = stream;
}
function handleError(error) {
console.error('Error: ', error);
}
// https://raw.githubusercontent.com/samdutton/simpl/gh-pages/getusermedia/sources/js/main.js
function setCameraResolution( track ){
width = track.getSettings().width
height = track.getSettings().height
$("#video").attr("width",width)
$("#video").attr("height",height)
$("#canvas").attr("width",width)
$("#canvas").attr("height",height)
}
// Put video listeners into place
if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia(mediaConfig).then(function(stream) {
//video.src = window.URL.createObjectURL(stream);
video.srcObject = stream;
setCameraResolution(stream.getVideoTracks()[0])
video.play();
});
}
/* Legacy code below! */
else if(navigator.getUserMedia) { // Standard
navigator.getUserMedia(mediaConfig, function(stream) {
setCameraResolution(stream.getVideoTracks()[0])
video.src = stream;
video.play();
}, errBack);
} else if(navigator.webkitGetUserMedia) { // WebKit-prefixed
navigator.webkitGetUserMedia(mediaConfig, function(stream){
setCameraResolution(stream.getVideoTracks()[0])
video.src = window.webkitURL.createObjectURL(stream);
video.play();
}, errBack);
} else if(navigator.mozGetUserMedia) { // Mozilla-prefixed
navigator.mozGetUserMedia(mediaConfig, function(stream){
setCameraResolution(stream.getVideoTracks()[0])
video.src = window.URL.createObjectURL(stream);
video.play();
}, errBack);
}
// Trigger photo take
@ -86,15 +169,13 @@ $(document).ready(function(){
}
$("#result").hide()
var slider = $( "#slider" ).slider({
$( "#slider" ).slider({
range: false,
value: 100,
animate: 300,
values: [ binary_level ],
min : 0,
max : 255,
change: function(event,ui){
binary_level = ui.value
console.log(`binary_level:${binary_level}`)
doContrast()
}
});
@ -104,7 +185,6 @@ $(document).ready(function(){
$("#messages").html('<div class="alert alert-primary" role="alert">Sending...</div>')
$.ajax({
timeout: 3000,
url: url + "/image",
method:"POST",
dataType: "json",
@ -119,7 +199,7 @@ $(document).ready(function(){
$("#messages").html(`<div class="alert alert-danger" role="alert">Something went wrong: ${msg}</div>`)
return
}
$("#messages").html(`<div class="alert alert-success" role="alert">OK, your image will be available in a few seconds as <a href="#${d.hash_name}" class="hash_name btn btn-sm btn-secondary">${d.hash_name}</a></div>`)
$("#messages").html(`<div class="alert alert-success" role="alert">OK, your image will be on ${d.hash_name}</div>`)
imageList = localStorage.getItem("imageList") ? JSON.parse(localStorage.getItem("imageList")) : []
imageList.push(d.hash_name)
localStorage.setItem("imageList",JSON.stringify(imageList))
@ -135,7 +215,8 @@ $(document).ready(function(){
var simuCanvas = document.getElementById("simuCanvas");
var ctx = simuCanvas.getContext("2d");
var lastpoint = { x: 0, y: 0, color: 0};
var zoom = 1;
ctx.clearRect(0,0,400,400);
var zoom = 0.5;
//ctx.save
Point = function( l ){
@ -151,7 +232,7 @@ $(document).ready(function(){
pointsList = document.pointsList
if (pointsList.length > 0)
{
ctx.clearRect(0,0,simuCanvas.width,simuCanvas.height);
ctx.clearRect(0,0,400,400);
lastpoint = new Point(pointsList[0])
for (var i = 0; i < pointsList.length; i+=1)
{
@ -182,22 +263,20 @@ $(document).ready(function(){
$("#preview").show()
html = ''
for( id in imageList.reverse()){
for( id in imageList){
hash_name = imageList[id]
html += `<li class="list-group-item"><a href="#${hash_name}" class="hash_name btn-sm btn btn-secondary" rel="${hash_name}">${hash_name}</a></li>`
html += `<li><a href="#${hash_name}" class="hash_name" rel="${hash_name}">${hash_name}</a></li>`
}
$("#imageList").html(`<ul class="list-group">${html}</ul>`)
$("#imageList").html(`<ul>${html}</ul>`)
}
refreshImageList()
var showImage = function(e){
var el = $(e.target)
if( ! el.hasClass("hash_name") ) { return; }
var hash_name = el.attr("rel")
$("#imageList").on("click",function(e){
var el = e.target
var hash_name = $(el).attr("rel")
var u = `${url}/hash_name/${hash_name}`
$.ajax({
timeout: 3000,
url: `${url}/hash_name/${hash_name}`,
dataType: "json",
@ -214,21 +293,8 @@ $(document).ready(function(){
.fail(function(d,m,jq){
$("#messages").html(`<div class="alert alert-danger" role="alert">Ooops... Something went wrong: ${jq}</div>`)
})
}
$("#imageList").on("click", showImage)
$("#messages").on("click", showImage)
$(".contrast").on("click",function(el){
let btn = el.target
let val = Number($(btn).attr("rel"))
let new_binary_level = binary_level + val;
console.log(`new_binary_level:${new_binary_level}`)
if( new_binary_level >= 0 && new_binary_level <= 255){
binary_level = new_binary_level
$("#slider").slider("option","value",binary_level)
}
})
})

View File

@ -6,7 +6,6 @@ import hashlib
import json
import os
import time
import sys
# Redis init
environ = os.environ
@ -15,7 +14,7 @@ port = environ['DB_PORT'] if 'DB_PORT' in os.environ else 6379
debug = environ['DEBUG'] if 'DEBUG' in os.environ else False
sep='**************************************'
print("\n{}\nConnecting to Redis server on {}:{}\n{}\n".format(sep,host,port,sep))
r = Redis(host=host, port=port)
r = Redis(host="db", port=port)
# hashlib init
m = hashlib.sha256()
@ -36,7 +35,6 @@ def image():
try:
data = dict()
res =r.keys("*")
# Clean the request
if "text" in request.form:
data["text"] = request.form["text"][:256]

View File

@ -11,7 +11,7 @@ rm -f /etc/nginx/sites-enabled/*
pip3 install flask numpy pillow redis
pip3 install pypotrace
cd /opt
#git clone https://git.interhacker.space/teamlaser/laser-app
git clone https://git.interhacker.space/teamlaser/laser-app
cp /opt/teamlaser/laser-app/files/nginx/sites-enabled/site.conf /etc/nginx/sites-enabled

View File

@ -14,7 +14,7 @@ color = 65280
environ = os.environ
host = environ['DB_HOST'] if 'DB_HOST' in os.environ else "localhost"
port = environ['DB_PORT'] if 'DB_PORT' in os.environ else 6379
r = Redis(host=host, port=port)
r = Redis(host="db", port=port)
def convertImg(src, image_path="/tmp/"):