Home > database >  Get Original Image Width And Height From A New Image() Object - JavaScript
Get Original Image Width And Height From A New Image() Object - JavaScript

Time:09-29

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 >SELECT FILES</p>
  </div>
  <div >
    <div >
      <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>

CodePudding user response:

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 >SELECT FILES</p>
  </div>
  <div >
    <div >
      <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>

CodePudding user response:

Yes, .width and .height will return the computed width and height of the element when it's visible in the doc.
Since your <img> element doesn't have an srcset attribute, you can use both its naturalWidth and naturalHeight to get the actual intrinsic size of the loaded image. If you had this srcset attribute though, these values could be divided by the size multiplier of the loaded source.

If you weren't displaying the image in a thumbnail, an efficient way to get the dimensions of the image would have been to call createImageBitmap() either on the File object you have directly, and to check the .width and .height properties of the resolved ImageBitmap object.

But since you do show the image, in your case that'd be overkill. Using .naturalWidth and .naturalHeight (after the image has loaded) is just enough.

  • Related