I have an image uploader where I have some PHP checks that happen on the server side. What I want to do is also provide frontend validations for the user, but I am having an issue getting the values to do the maths for the image resolution in megapixels. On the server side I can just use the file's width and height properties and then multiply them.
The problem I have is on the frontend when using a new Image()
object, when I get the width and height properties it gives me the values of the image file in the container, not the width and height values of the source file / original image.
I thought I could just use the .src
property and get the size of that instead, but this doesn't work either.
In the code below as you can see the Image()
object is assigned to a thumbnailElement
variable.
If you click the Select Files
button and add an image it will show the thumbnails and log the original file size to the console, but not the original width ?
Note: the updateThumbnail() function is invoked in the HTML
Codepen Link: https://codepen.io/thechewy/pen/yLjvqWe
var zone = document.getElementById("zone"),
selectedImagesContainer = document.getElementById("show-selected-images"),
fileUploader = document.getElementById("standard-upload-files");
zone.addEventListener("click", (e) => {
// assigns the zone element to the hidden input element so when you click 'select files' it brings up a file picker window
fileUploader.click();
});
fileUploader.addEventListener("change", (e) => {
// this function is further down but declared here and shows a thumbnail of the image
[...fileUploader.files].forEach(updateThumbnail);
});
function updateThumbnail(file) {
let uploadImageWrapper = document.createElement("figure"), // image wrapper <figure> element
thumbnailElement = new Image(); // image
// image thumbnail
thumbnailElement.classList.add("thumbnail");
thumbnailElement.src = URL.createObjectURL(file);
// appending elements
selectedImagesContainer.append(uploadImageWrapper); // append <figure> element
uploadImageWrapper.append(thumbnailElement); // append image thumbnail
console.log("file size is: ", file.size);
console.log("file width is: ", thumbnailElement.width);
} // end of 'updateThumbnail' function
body {
margin: 0;
display: flex;
justify-content: center;
font-family: arial;
}
form {
width: 50%;
max-width: 600px;
}
.select-files {
padding: 1rem;
background: red;
cursor: pointer;
color: #fff;
font-weight: bold;
}
#show-selected-images {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin-top: 2rem;
}
figure {
width: 100%;
margin: 0;
}
img {
display: block;
width: 100%;
height: auto;
}
<form id="upload-images-form" enctype="multipart/form-data" method="post">
<h1>Upload Your Images</h1>
<div id="zone">
<p class="select-files">SELECT FILES</p>
</div>
<div class="inner-wrapper">
<div class="upload-label-wrapper">
<input id="standard-upload-files" style="display:none;" type="file" name="standard-upload-files[]" multiple>
</div>
<button id="submit-images" oninput="updateThumbnail(this.files)">SUBMIT IMAGES</button>
</div>
<div id="show-selected-images"></div>
</form>
You need the naturalWidth property to get actual image width in pixels, also to get that value reliably you should use the HTMLImageElement.decode() method that returns a promise which is resolved once the full-resolution image is fully decoded, like this:
var zone = document.getElementById("zone"),
selectedImagesContainer = document.getElementById("show-selected-images"),
fileUploader = document.getElementById("standard-upload-files");
zone.addEventListener("click", (e) => {
// assigns the zone element to the hidden input element so when you click 'select files' it brings up a file picker window
fileUploader.click();
});
fileUploader.addEventListener("change", (e) => {
// this function is further down but declared here and shows a thumbnail of the image
[...fileUploader.files].forEach(updateThumbnail);
});
function updateThumbnail(file) {
let uploadImageWrapper = document.createElement("figure"), // image wrapper <figure> element
thumbnailElement = new Image(); // image
// image thumbnail
thumbnailElement.classList.add("thumbnail");
thumbnailElement.src = URL.createObjectURL(file);
// appending elements
selectedImagesContainer.append(uploadImageWrapper); // append <figure> element
uploadImageWrapper.append(thumbnailElement); // append image thumbnail
console.log("file size is: ", file.size);
thumbnailElement.decode().then(() => {
console.log("file width is: ", thumbnailElement.naturalWidth);
}).catch((encodingError) => {
// Do something with the error.
});
} // end of 'updateThumbnail' function
body {
margin: 0;
display: flex;
justify-content: center;
font-family: arial;
}
form {
width: 50%;
max-width: 600px;
}
.select-files {
padding: 1rem;
background: red;
cursor: pointer;
color: #fff;
font-weight: bold;
}
#show-selected-images {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
margin-top: 2rem;
}
figure {
width: 100%;
margin: 0;
}
img {
display: block;
width: 100%;
height: auto;
}
<form id="upload-images-form" enctype="multipart/form-data" method="post">
<h1>Upload Your Images</h1>
<div id="zone">
<p class="select-files">SELECT FILES</p>
</div>
<div class="inner-wrapper">
<div class="upload-label-wrapper">
<input id="standard-upload-files" style="display:none;" type="file" name="standard-upload-files[]" multiple>
</div>
<button id="submit-images" oninput="updateThumbnail(this.files)">SUBMIT IMAGES</button>
</div>
<div id="show-selected-images"></div>
</form>