Webcam support to use it as a photomaton ( photobooth ) #2
21
src/templates/banner.html
Normal file
21
src/templates/banner.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<body class="container">
|
||||||
|
<div class="col-md-7 offset-md-2">
|
||||||
|
<a href="/"><img class="rounded" width="100px" src="{{ url_for('static', filename='images/little-printer.png') }}" alt="LittlePrynter icon"></a><h1 class="card-title font-weight-bold">Little Prynter</h1>
|
||||||
|
<hr>
|
||||||
|
<div class="alert alert-dark" role="alert">LittlePrynter is under heavy developpement, you may encounter bugs ! If so, try again. Thanks !</div>
|
||||||
|
<br>
|
||||||
|
{% with messages = get_flashed_messages(category_filter=('error')) %}
|
||||||
|
{% if messages %}
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="alert alert-danger" role="alert">⚠️ {{ message }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
|
{% with messages = get_flashed_messages(category_filter=('info')) %}
|
||||||
|
{% if messages %}
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="alert alert-info" role="alert">ℹ️ {{ message }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
57
src/templates/base.html
Normal file
57
src/templates/base.html
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>LittlePrynter</title>
|
||||||
|
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static',filename='css/style.css') }}">
|
||||||
|
</head>
|
||||||
|
<body class="container">
|
||||||
|
<div class="col-auto">
|
||||||
|
<a href="/"><img class="rounded" width="100px" src="{{ url_for('static', filename='images/little-printer.png') }}" alt="LittlePrynter icon"></a><h1 class="card-title font-weight-bold">Little Prynter</h1>
|
||||||
|
<hr>
|
||||||
|
<nav class="navbar navbar-expand-lg navbar-light bg-light">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link active" aria-current="page" href="/">Home</a>
|
||||||
|
</li>
|
||||||
|
<li class="nav-item">
|
||||||
|
<a class="nav-link" href="/webcam">Webcam</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<div class="alert alert-dark" role="alert">LittlePrynter is under heavy developpement, you may encounter bugs ! If so, try again. Thanks !</div>
|
||||||
|
<br>
|
||||||
|
{% with messages = get_flashed_messages(category_filter=('error')) %}
|
||||||
|
{% if messages %}
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="alert alert-danger" role="alert">⚠️ {{ message }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
|
{% with messages = get_flashed_messages(category_filter=('info')) %}
|
||||||
|
{% if messages %}
|
||||||
|
{% for message in messages %}
|
||||||
|
<div class="alert alert-info" role="alert">ℹ️ {{ message }}</div>
|
||||||
|
{% endfor %}
|
||||||
|
{% endif %}
|
||||||
|
{% endwith %}
|
||||||
|
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
|
||||||
|
{% endblock %}
|
||||||
|
<hr>
|
||||||
|
<footer>Little Prynter is built by <a href="https://n07070.xyz/about-me/">n07070</a> because it's fun :) | <a href="https://git.n07070.xyz/n07070/littleprynter/src/branch/epson-tm-t20iii">Source code - AGPLv3</a></footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,5 @@
|
|||||||
|
<hr>
|
||||||
|
<footer>Little Prynter is built by <a href="https://n07070.xyz/about-me/">n07070</a> because it's fun :) | <a href="https://git.n07070.xyz/n07070/littleprynter/src/branch/epson-tm-t20iii">Source code - AGPLv3</a></footer>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,10 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>LittlePrynter</title>
|
||||||
|
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||||
|
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static',filename='css/style.css') }}">
|
||||||
|
</head>
|
@ -1,40 +1,7 @@
|
|||||||
<!DOCTYPE html>
|
{% extends 'base.html' %}
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8">
|
|
||||||
<title>LittlePrynter</title>
|
|
||||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
||||||
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
|
|
||||||
<link rel="stylesheet" href="{{ url_for('static',filename='css/style.css') }}">
|
|
||||||
</head>
|
|
||||||
<body class="container">
|
|
||||||
<div class="col-md-7 offset-md-2">
|
|
||||||
<a href="/"><img class="rounded" width="100px" src="{{ url_for('static', filename='images/little-printer.png') }}" alt="LittlePrynter icon"></a><h1 class="card-title font-weight-bold">Little Prynter</h1>
|
|
||||||
<hr>
|
|
||||||
<div class="alert alert-dark" role="alert">LittlePrynter is under heavy developpement, you may encounter bugs ! If so, try again. Thanks !</div>
|
|
||||||
<br>
|
|
||||||
{% with messages = get_flashed_messages(category_filter=('error')) %}
|
|
||||||
{% if messages %}
|
|
||||||
{% for message in messages %}
|
|
||||||
<div class="alert alert-danger" role="alert">⚠️ {{ message }}</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
|
|
||||||
{% with messages = get_flashed_messages(category_filter=('info')) %}
|
{% block content %}
|
||||||
{% if messages %}
|
|
||||||
{% for message in messages %}
|
|
||||||
<div class="alert alert-info" role="alert">ℹ️ {{ message }}</div>
|
|
||||||
{% endfor %}
|
|
||||||
{% endif %}
|
|
||||||
{% endwith %}
|
|
||||||
|
|
||||||
<!-- <br>
|
|
||||||
<h3>Imprimer une image aléatoire</h3>
|
|
||||||
<a class="btn btn-primary btn-lg" href="/api/print/image"> Imprimer</a>
|
|
||||||
<hr>
|
|
||||||
<br> -->
|
|
||||||
<div class="card">
|
<div class="card">
|
||||||
<h3 class="card-header">Print a short message</h3>
|
<h3 class="card-header">Print a short message</h3>
|
||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
@ -60,12 +27,4 @@
|
|||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div id="pbar" style="display:none">
|
{% endblock %}
|
||||||
<img src="{{ url_for('static',filename='load.gif') }}" alt="loading wheel">
|
|
||||||
</div> -->
|
|
||||||
</div>
|
|
||||||
<hr>
|
|
||||||
<footer>Little Prynter is built by <a href="https://n07070.xyz/about-me/">n07070</a> because it's fun :) | <a href="https://git.n07070.xyz/n07070/littleprynter/src/branch/epson-tm-t20iii">Source code - AGPLv3</a></footer>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
186
src/templates/webcam.html
Normal file
186
src/templates/webcam.html
Normal file
@ -0,0 +1,186 @@
|
|||||||
|
{% extends 'base.html' %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
|
||||||
|
<div class="card">
|
||||||
|
<h3 class="card-header">Photomaton</h3>
|
||||||
|
<div class="card-body row">
|
||||||
|
|
||||||
|
<canvas id="canvas"></canvas>
|
||||||
|
<video id="video" class="align-self-center">Video stream not available.</video>
|
||||||
|
<div class="image_dither">
|
||||||
|
<picture>
|
||||||
|
<img id="photo" class="align-self-center">
|
||||||
|
</picture>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
<!-- <div class="row row-cols-2"> -->
|
||||||
|
<!-- <button class="align-self-center col-3 btn btn-danger" name="take_picture" id="startbutton">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="54" height="54" fill="currentColor" class="bi bi-camera" viewBox="0 0 16 16">
|
||||||
|
<path d="M15 12a1 1 0 0 1-1 1H2a1 1 0 0 1-1-1V6a1 1 0 0 1 1-1h1.172a3 3 0 0 0 2.12-.879l.83-.828A1 1 0 0 1 6.827 3h2.344a1 1 0 0 1 .707.293l.828.828A3 3 0 0 0 12.828 5H14a1 1 0 0 1 1 1v6zM2 4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2h-1.172a2 2 0 0 1-1.414-.586l-.828-.828A2 2 0 0 0 9.172 2H6.828a2 2 0 0 0-1.414.586l-.828.828A2 2 0 0 1 3.172 4H2z"/>
|
||||||
|
<path d="M8 11a2.5 2.5 0 1 1 0-5 2.5 2.5 0 0 1 0 5zm0 1a3.5 3.5 0 1 0 0-7 3.5 3.5 0 0 0 0 7zM3 6.5a.5.5 0 1 1-1 0 .5.5 0 0 1 1 0z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<br><br> -->
|
||||||
|
<button class="align-self-center col-3 btn btn-danger" name="print_picture" id="print_button">
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" width="54" height="54" fill="currentColor" class="bi bi-printer" viewBox="0 0 16 16">
|
||||||
|
<path d="M2.5 8a.5.5 0 1 0 0-1 .5.5 0 0 0 0 1z"/>
|
||||||
|
<path d="M5 1a2 2 0 0 0-2 2v2H2a2 2 0 0 0-2 2v3a2 2 0 0 0 2 2h1v1a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2v-1h1a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-1V3a2 2 0 0 0-2-2H5zM4 3a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1v2H4V3zm1 5a2 2 0 0 0-2 2v1H2a1 1 0 0 1-1-1V7a1 1 0 0 1 1-1h12a1 1 0 0 1 1 1v3a1 1 0 0 1-1 1h-1v-1a2 2 0 0 0-2-2H5zm7 2v3a1 1 0 0 1-1 1H5a1 1 0 0 1-1-1v-3a1 1 0 0 1 1-1h6a1 1 0 0 1 1 1z"/>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<!-- </div> -->
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style media="screen">
|
||||||
|
canvas {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
video {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image_dither {
|
||||||
|
/* width: 300px;
|
||||||
|
height: 400px; */
|
||||||
|
image-rendering: smooth;
|
||||||
|
filter: saturate(0) contrast(250);
|
||||||
|
}
|
||||||
|
|
||||||
|
picture {
|
||||||
|
image-rendering: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image_dither > picture::after {
|
||||||
|
content: '';
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
pointer-events: none;
|
||||||
|
position: fixed;
|
||||||
|
display: block;
|
||||||
|
z-index: 2;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAYAAACp8Z5+AAAAOklEQVR4nC3KQQFAQAAAwd0EIohANA0uiiiugQgiiLA+5j0AVBewVa/VUGd1qBNgrR5gqW6r8x+7Oj8/xCBur9LU/wAAAABJRU5ErkJggg==');
|
||||||
|
background-repeat: repeat;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#photo {
|
||||||
|
background: linear-gradient(90deg, #00C9FF 0%, #92FE9D 100%);
|
||||||
|
padding: 0;
|
||||||
|
max-width: 100%;
|
||||||
|
vertical-align: middle;
|
||||||
|
image-rendering: pixelated;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script type="text/javascript">
|
||||||
|
let streaming;
|
||||||
|
var width = document.getElementById("video").parentNode.parentElement.clientWidth;
|
||||||
|
var height = width / (4 / 3);
|
||||||
|
function startup() {
|
||||||
|
video = document.getElementById('video');
|
||||||
|
canvas = document.getElementById('canvas');
|
||||||
|
photo = document.getElementById('photo');
|
||||||
|
printButton = document.getElementById('print_button');
|
||||||
|
|
||||||
|
// access video stream from webcam
|
||||||
|
navigator.mediaDevices.getUserMedia({
|
||||||
|
video: true,
|
||||||
|
audio: false
|
||||||
|
})
|
||||||
|
// on success, stream it in video tag
|
||||||
|
// the video tag is hidden, as is the canvas.
|
||||||
|
.then(function(stream) {
|
||||||
|
video.srcObject = stream;
|
||||||
|
video.play();
|
||||||
|
})
|
||||||
|
.catch(function(err) {
|
||||||
|
console.log("An error occurred: " + err);
|
||||||
|
});
|
||||||
|
|
||||||
|
video.addEventListener('canplay', function(ev) {
|
||||||
|
if (!streaming) {
|
||||||
|
height = video.videoHeight / (video.videoWidth / width);
|
||||||
|
|
||||||
|
if (isNaN(height)) {
|
||||||
|
height = width / (4 / 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
video.setAttribute('width', width);
|
||||||
|
video.setAttribute('height', height);
|
||||||
|
canvas.setAttribute('width', width);
|
||||||
|
canvas.setAttribute('height', height);
|
||||||
|
|
||||||
|
photo.setAttribute('width', width);
|
||||||
|
photo.setAttribute('height', height);
|
||||||
|
|
||||||
|
|
||||||
|
streaming = true;
|
||||||
|
}
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
printButton.addEventListener('click', function(ev){
|
||||||
|
data = takepicture();
|
||||||
|
printPicture(data)
|
||||||
|
ev.preventDefault();
|
||||||
|
|
||||||
|
}, false)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function clearphoto() {
|
||||||
|
var context = canvas.getContext('2d');
|
||||||
|
context.fillStyle = "#AAA";
|
||||||
|
context.fillRect(0, 0, canvas.width, canvas.height);
|
||||||
|
|
||||||
|
var data = canvas.toDataURL('image/png');
|
||||||
|
photo.setAttribute('src', data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function takepicture() {
|
||||||
|
var context = canvas.getContext('2d');
|
||||||
|
if (width && height) {
|
||||||
|
canvas.width = width;
|
||||||
|
canvas.height = height;
|
||||||
|
context.drawImage(video, 0, 0, width, height);
|
||||||
|
|
||||||
|
var data = canvas.toDataURL('image/png');
|
||||||
|
photo.setAttribute('src', data);
|
||||||
|
} else {
|
||||||
|
clearphoto();
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function printPicture(data){
|
||||||
|
var url = "/api/print/img"
|
||||||
|
var picture = data;
|
||||||
|
const formData = new FormData();
|
||||||
|
|
||||||
|
formData.append("file", picture);
|
||||||
|
|
||||||
|
fetch(url, {
|
||||||
|
method: 'POST', // or 'PUT'
|
||||||
|
body: formData,
|
||||||
|
headers:{
|
||||||
|
'Content-Type': 'multipart/form-data'
|
||||||
|
}
|
||||||
|
}).then(response => console.log('Success:', response), true)
|
||||||
|
.catch(error => console.error('Error:', error), false);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('load', startup, false);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<br>
|
||||||
|
|
||||||
|
{% endblock %}
|
Loading…
Reference in New Issue
Block a user