I am currently working on an "Dynamic Slideshow". I want to run a python script, which shows images in an directory. With a small interface you can add new images to the slideshow.
For the interface I am using an vanilla HTML / CSS / JavaScript app. To get the input, I am using <input id="image-input" type="file" accept="image/*" onchange="showPreview()">
element. But sometime, I have to select a picture twice or take it twice or even more often. Sometimes I'll get an error which says something with "too less storage for the last operation" or something like this. Unfortunately, I am unable to reproduce this since it happens randomly.
I tried to find a reason, but it seems to happen randomly. It doens't occur on a specific image or if a file is too big or something. The only thing I noticed is, that if I take an image with the camera, I have to take it mostly twice. But the second time it works.
Here is my showPreview()
function:
/**
* Show a preview of the image
*/
function showPreview() {
// get the input element and select the first image
const input = document.getElementById("image-input");
const image = input.files[0];
// get the preview image and set the src attribute
const imgTag = document.getElementById("preview");
imgTag.src = URL.createObjectURL(image);
// show submit button
const submitButton = document.getElementById("submit-btn");
submitButton.style.visibility = "visible";
}
The whole code is availabel in GitHub
Removing the additional onclick
event from the img
tag fixes it while maintaining same functionality:
<div id="image-container" onclick="selectImage(false)">
<img id="preview" alt="Es wurde noch kein Foto ausgewählt" src="UploadIcon.png" />
</div>
/**
* Open a dialog to select an image from the device
* @param {boolean} openCamera True, if the capture tag should be added to the input field to open the camera
*/
function selectImage(openCamera) {
const input = document.getElementById("image-input");
if (openCamera) {
input.setAttribute("capture", "camera");
}
else {
input.removeAttribute("cature");
}
// trigger the click event of the input to select a Image
input.click();
}
/**
* Show a preview of the image
*/
function showPreview() {
// get the input element and select the first image
const input = document.getElementById("image-input");
const image = input.files[0];
// get the preview image and set the src attribute
const imgTag = document.getElementById("preview");
imgTag.src = URL.createObjectURL(image);
// show submit button
const submitButton = document.getElementById("submit-btn");
submitButton.style.visibility = "visible";
}
/**
* Submit image to API
*/
function submit() {
// image to submit
const input = document.getElementById("image-input");
const image = input.files[0];
// API URL
const url = "http://" + window.location.hostname + ":8000";
// create FormData and add image
const formData = new FormData();
formData.append("image", image);
// send POST-Request
fetch(url, {
method: "POST",
body: formData
})
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
if(data.msg === "Success"){
// show message box with success text
const msgBox = document.getElementById("msg-box");
msgBox.style.visibility = "visible";
// disable pointer events
const container = document.getElementById("container");
container.style.pointerEvents = "none";
}
else {
alert(data);
}
})
.catch((error) => {
alert(error);
});
}
/**
* Close the message box displaying feedback from the API
*/
function closeMessageBox() {
// hide message box with success text
const msgBox = document.getElementById("msg-box");
msgBox.style.visibility = "hidden";
// enable pointer events
const container = document.getElementById("container");
container.style.pointerEvents = "all";
// reset preview
const imgTag = document.getElementById("preview");
imgTag.src = "UploadIcon.png";
// reset input to prevent storing hundreds of images
const imgInput = document.getElementById("image-input");
imgInput.value = "";
// hide submit button
const submitButton = document.getElementById("submit-btn");
submitButton.style.visibility = "hidden";
}
body {
display: flex;
font-family: Arial, sans-serif;
}
h2 {
white-space: nowrap;
margin: auto;
}
.container {
margin: 0 auto;
padding: 0.5em;
text-align: center;
max-width: 500px;
pointer-events: all;
}
#buttons-container{
display: flex;
flex-direction: row;
justify-content: space-between;
}
.image-upload-button{
width: calc(50% - 0.5em);
height: 2em;
}
#image-input{
visibility: hidden;
}
#container-preview {
max-width: 100%;
margin-top: 20px;
text-align: left;
}
#image-container{
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
min-width: 150px;
width: 100%;
min-height: 150px;
height: 100%;
border: 1px solid lightgray;
border-radius: 1em;
}
#preview{
width: auto;
max-width: 100%;
height: auto;
max-height: 100%;
aspect-ratio: 1 / 1;
object-fit: contain;
}
#submit-btn{
width: 100%;
height: 2em;
visibility: hidden;
margin-top: 1em;
}
#msg-box{
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: whitesmoke;
width: 90vw;
max-width: 450px;
aspect-ratio: 2 / 1;
border-radius: 1.5em;
border: 1px solid black;
box-shadow: 5px 5px 20px 1px rgba(0, 0, 0, 0.5);
display: grid;
grid-template-rows: 1em 2fr 4fr 2fr 1em;
grid-template-columns: 1em 2fr 4fr 2fr 1em;
visibility: hidden;
}
#header{
grid-row: 2 / 3;
grid-column: 2 / 5;
position: absolute;
bottom: 0;
left: 0;
font-weight: bold;
font-size: 1.5em;
margin: 0;
}
#msg {
grid-row: 3 / 4;
grid-column: 2 / 5;
font-size: 1em;
margin: 0;
display: flex;
flex-direction: column;
justify-content: center;
}
#ok-btn{
grid-row: 4 / 5;
grid-column: 4 / 5;
border-radius: 0.5em;
}
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Dynamic Slideshow</title>
<link rel="icon" href="Icon.ico" sizes="48x48">
<link rel="stylesheet" href="index.css">
<script type="text/javascript" src="index.js"></script>
</head>
<body>
<div id="container" class="container">
<h2>Willkommen</h2>
<h2>zum 50. Geburtstag</h2>
<h2>von Böbber / Strohmi / Michael</h2>
<p>Du möchtes einen Moment von der Feier mit allen teilen?</p>
<p>Dann nimm ein Schnappschuss auf, lade ihn hoch und werde ein Teil der Diashow!</p>
<div id="buttons-container">
<button class="image-upload-button" onclick="selectImage(false)">Bild auswählen</button>
<button class="image-upload-button" onclick="selectImage(true)">Bild aufnehmen</button>
</div>
<input id="image-input" type="file" accept="image/*" onchange="showPreview()">
<div id="container-preview">
<p>Vorschau:</p>
<div id="image-container" onclick="selectImage(false)">
<img id="preview" alt="Es wurde noch kein Foto ausgewählt" src="UploadIcon.png" />
</div>
<button id="submit-btn" onclick="submit()">Hochladen</button>
</div>
</div>
<div id="msg-box">
<p id="header">Super!</p>
<p id="msg">Der Upload war erfolgreich. Schaue zur Show. Das Bild ist bald zu sehen!</p>
<button id="ok-btn" onclick="closeMessageBox()">Ok</button>
</div>
</body>
</html>