javascriptimagecreateobjecturl

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


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>


Solution

  • 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>