Check image width and height before upload with Javascript
Asked Answered
F

11

208

I have a JPS with a form in which a user can put an image:

<div class="photo">
    <div>Photo (max 240x240 and 100 kb):</div>
    <input type="file" name="photo" id="photoInput" onchange="checkPhoto(this)"/>
</div>

I have written this js:

function checkPhoto(target) {
    if(target.files[0].type.indexOf("image") == -1) {
        document.getElementById("photoLabel").innerHTML = "File not supported";
        return false;
    }
    if(target.files[0].size > 102400) {
        document.getElementById("photoLabel").innerHTML = "Image too big (max 100kb)";
        return false;
    }
    document.getElementById("photoLabel").innerHTML = "";
    return true;
}

which works fine to check file type and size. Now I want to check image width and height but I cannot do it.
I have tried with target.files[0].width but I get undefined. With other ways I get 0.
Any suggestions?

Francium answered 18/1, 2012 at 0:57 Comment(0)
G
294

The file is just a file, you need to create an image like so:

var _URL = window.URL || window.webkitURL;
$("#file").change(function (e) {
    var file, img;
    if ((file = this.files[0])) {
        img = new Image();
        var objectUrl = _URL.createObjectURL(file);
        img.onload = function () {
            alert(this.width + " " + this.height);
            _URL.revokeObjectURL(objectUrl);
        };
        img.src = objectUrl;
    }
});

Demo: http://jsfiddle.net/4N6D9/1/

I take it you realize this is only supported in a few browsers. Mostly firefox and chrome, could be opera as well by now.

P.S. The URL.createObjectURL() method has been removed from the MediaStream interface. This method has been deprecated in 2013 and superseded by assigning streams to HTMLMediaElement.srcObject. The old method was removed because it is less safe, requiring a call to URL.revokeOjbectURL() to end the stream. Other user agents have either deprecated (Firefox) or removed (Safari) this feature feature.

For more information, please refer here.

Ghazi answered 18/1, 2012 at 1:22 Comment(4)
definately it will not work on safari unless you have safari 6.0. 6.0 is the only version that support file API as of now. And I don't think apple ever gonna release 6.0 for windows. 5.1.7 have been the latest verson of safari from soooo long agoLiberty
It works in IE10, but doesn't seem to work in IE9 and Below. And that is because IE9 and below do not support the File API (caniuse.com/#search=file%20api)Easily
Evem though this example works well in pure javascript but you had better come up with the one that works on Angular though since Angular cannot accept the anonymous function. Better replace the anonymous function with function arrow instead.Perquisite
Content Security Policy prevent this solutionBazil
S
80

In my view the perfect answer you must required is

var reader = new FileReader();

//Read the contents of Image File.
reader.readAsDataURL(fileUpload.files[0]);
reader.onload = function (e) {

  //Initiate the JavaScript Image object.
  var image = new Image();

  //Set the Base64 string return from FileReader as source.
  image.src = e.target.result;

  //Validate the File Height and Width.
  image.onload = function () {
    var height = this.height;
    var width = this.width;
    if (height > 100 || width > 100) {
      alert("Height and Width must not exceed 100px.");
      return false;
    }
    alert("Uploaded image has valid Height and Width.");
    return true;
  };
};
Skep answered 13/12, 2017 at 6:4 Comment(4)
A good answer, since it does not require createObjectUrl. Can be improved to use reader.result instead of e.target.result and should use reader.onloadend instead of onload combined with reader.onerror to handle errorsHenleigh
I tried the code with an image file of 13 MB. It takes up to 2 seconds within the browser to process and return the width/height. The top answer, however, gets the image dimensions in a few milliseconds.Pun
@Pun you should state who posted the top answer, since the top answer changes over time.Dipsomaniac
Good point. The answer I mean: https://mcmap.net/q/126432/-check-image-width-and-height-before-upload-with-javascriptPun
A
45

I agree. Once it is uploaded to somewhere the user's browser can access then it is pretty easy to get the size. As you need to wait for the image to load you'll want to hook into the onload event for img.

Updated example:


// async/promise function for retrieving image dimensions for a URL
function imageSize(url) {
    const img = document.createElement("img");

    const promise = new Promise((resolve, reject) => {
      img.onload = () => {
        // Natural size is the actual image size regardless of rendering.
        // The 'normal' `width`/`height` are for the **rendered** size.
        const width  = img.naturalWidth;
        const height = img.naturalHeight; 

        // Resolve promise with the width and height
        resolve({width, height});
      };

      // Reject promise on error
      img.onerror = reject;
    });

    // Setting the source makes it start downloading and eventually call `onload`
    img.src = url;

    return promise;
}

// How to use in an async function
(async() => {
  const imageUrl = 'http://your.website.com/userUploadedImage.jpg';
  const imageDimensions = await imageSize(imageUrl);

  console.info(imageDimensions); // {width: 1337, height: 42}
})();

Older example:

var width, height;

var img = document.createElement("img");
img.onload = function() {
    // `naturalWidth`/`naturalHeight` aren't supported on <IE9. Fallback to normal width/height
    // The natural size is the actual image size regardless of rendering.
    // The 'normal' width/height are for the **rendered** size.
    
    width  = img.naturalWidth  || img.width;
    height = img.naturalHeight || img.height; 
    
    // Do something with the width and height
}

// Setting the source makes it start downloading and eventually call `onload`
img.src = "http://your.website.com/userUploadedImage.jpg";
Auxiliaries answered 18/1, 2012 at 1:4 Comment(1)
what about when you need them specifically prior to load for aspect ratio calculations to prevent cumulative layout shiftJulietjulieta
H
36

This is the easiest way to check the size

let img = new Image()
img.src = window.URL.createObjectURL(event.target.files[0])
img.onload = () => {
   alert(img.width + " " + img.height);
}

Check for specific size. Using 100 x 100 as example

let img = new Image()
img.src = window.URL.createObjectURL(event.target.files[0])
img.onload = () => {
   if(img.width === 100 && img.height === 100){
        alert(`Nice, image is the right size. It can be uploaded`)
        // upload logic here
        } else {
        alert(`Sorry, this image doesn't look like the size we wanted. It's 
   ${img.width} x ${img.height} but we require 100 x 100 size image.`);
   }                
}
Haith answered 17/11, 2019 at 2:47 Comment(1)
Remember to call URL.revokeObjectURL() to avoid memory leaks. developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURLDomineering
H
13

I think this may be the simplest for uploads if you want to use it other functions.

async function getImageDimensions(file) {
    let img = new Image();
    img.src = URL.createObjectURL(file);
    await img.decode();
    let width = img.width;
    let height = img.height;
    return {
        width,
        height,
    }
  }

Use like

 const {width, height } = await getImageDimensions(file)

Suppose you were storing an image for Tiger taken in Kenya. So you could use it like to upload to cloud storage and then store photo information.

const addImage = async (file, title, location) => {
   const { width, height } = await getImageDimensions(file)
   
   const url = await uploadToCloudStorage(file) // returns storage url

   await addToDatabase(url, width, height, title, location)
}
Hamhung answered 22/12, 2022 at 4:8 Comment(0)
W
6

Attach the function to the onchange method of the input type file /onchange="validateimg(this)"/

   function validateimg(ctrl) { 
        var fileUpload = ctrl;
        var regex = new RegExp("([a-zA-Z0-9\s_\\.\-:])+(.jpg|.png|.gif)$");
        if (regex.test(fileUpload.value.toLowerCase())) {
            if (typeof (fileUpload.files) != "undefined") {
                var reader = new FileReader();
                reader.readAsDataURL(fileUpload.files[0]);
                reader.onload = function (e) {
                    var image = new Image();
                    image.src = e.target.result;
                    image.onload = function () {
                        var height = this.height;
                        var width = this.width;
                        if (height < 1100 || width < 750) {
                            alert("At least you can upload a 1100*750 photo size.");
                            return false;
                        }else{
                            alert("Uploaded image has valid Height and Width.");
                            return true;
                        }
                    };
                }
            } else {
                alert("This browser does not support HTML5.");
                return false;
            }
        } else {
            alert("Please select a valid Image file.");
            return false;
        }
    }
Wedlock answered 8/6, 2019 at 13:52 Comment(0)
D
5

    const ValidateImg = (file) =>{
        let img = new Image()
        img.src = window.URL.createObjectURL(file)
        img.onload = () => {
            if(img.width === 100 && img.height ===100){
                alert("Correct size");
                return true;
            }
            alert("Incorrect size");
            return true;
        }
    }
Disposal answered 27/3, 2020 at 15:2 Comment(0)
B
4
function validateimg(ctrl) {
    var fileUpload = $("#txtPostImg")[0];
    var regex = new RegExp("([a-zA-Z0-9\s_\\.\-:])+(.jpg|.png|.gif)$");
    if (regex.test(fileUpload.value.toLowerCase())) {
        if (typeof (fileUpload.files) != "undefined") {
            var reader = new FileReader();
            reader.readAsDataURL(fileUpload.files[0]);
            reader.onload = function (e) {
                var image = new Image();
                image.src = e.target.result;
                image.onload = function () {
                    var height = this.height;
                    var width = this.width;
                    console.log(this);
                    if ((height >= 1024 || height <= 1100) && (width >= 750 || width <= 800)) {
                        alert("Height and Width must not exceed 1100*800.");
                        return false;
                    }
                    alert("Uploaded image has valid Height and Width.");
                    return true;
                };
            }
        } else {
            alert("This browser does not support HTML5.");
            return false;
        }
    } else {
        alert("Please select a valid Image file.");
        return false;
    }
}
Beastly answered 11/9, 2018 at 9:47 Comment(1)
Please try to format complete code and provide a little description of what you did in your code.Harmonious
R
2

You can do the steps for previewing the image without showing it which is supported on all browsers. Following js code shows you how to check the width and height :

var file = e.target.files[0];
if (/\.(jpe?g|png|gif)$/i.test(file.name)) {
    var reader = new FileReader();
    reader.addEventListener("load", function () {
        var image = new Image();
        image.src = this.result as string;
        image.addEventListener('load', function () {
            console.log(`height: ${this.height}, width: ${this.width}`);
        });
                
    }, false);
            
    reader.readAsDataURL(file);
}

Based on Mozilla docs:

The readAsDataURL method is used to read the contents of the specified Blob or File. When the read operation is finished, the readyState becomes DONE, and the loadend is triggered. At that time, the result attribute contains the data as a data: URL representing the file's data as a base64 encoded string.

And the browser compatibility is listed too.

Rodie answered 26/11, 2020 at 6:9 Comment(0)
A
2

In my case, I needed to also prevent the form from being submited, so here is the solution that worked for me.

The preventDefault will stop the form action, then we check the size and dimensions of the image in the onload function.

If all good, we allow the submit.

As the submit button gets disabled if a user still tries to submit the form with an invalid image, I also had to re-able the submit button once a valid image is inputted.

const validateMaxImageFileSize = (e) => {
  e.preventDefault();
  const el = $("input[type='file']")[0];

  if (el.files && el.files[0]) {
    const file = el.files[0];

    const maxFileSize = 5242880; // 5 MB
    const maxWidth = 1920;
    const maxHeight = 1080;

    const img = new Image();
    img.src = window.URL.createObjectURL(file);
    img.onload = () => {
      if (file.type.match('image.*') && file.size > maxFileSize) {
        alert('The selected image file is too big. Please choose one that is smaller than 5 MB.');
      } else if (file.type.match('image.*') && (img.width > maxWidth || img.height > maxHeight)) {
        alert(`The selected image is too big. Please choose one with maximum dimensions of ${maxWidth}x${maxHeight}.`);
      } else {
        e.target.nodeName === 'INPUT'
          ? (e.target.form.querySelector("input[type='submit']").disabled = false)
          : e.target.submit();
      }
    };
  }
};

$('form.validate-image-size').on('submit', validateMaxImageFileSize);
$("form.validate-image-size input[type='file']").on('change', validateMaxImageFileSize);
Apodal answered 8/4, 2021 at 11:57 Comment(0)
B
-1
function uploadfile(ctrl) {
    var validate = validateimg(ctrl);

    if (validate) {
        if (window.FormData !== undefined) {
            ShowLoading();
            var fileUpload = $(ctrl).get(0);
            var files = fileUpload.files;


            var fileData = new FormData();


            for (var i = 0; i < files.length; i++) {
                fileData.append(files[i].name, files[i]);
            }


            fileData.append('username', 'Wishes');

            $.ajax({
                url: 'UploadWishesFiles',
                type: "POST",
                contentType: false,
                processData: false,
                data: fileData,
                success: function(result) {
                    var id = $(ctrl).attr('id');
                    $('#' + id.replace('txt', 'hdn')).val(result);

                    $('#imgPictureEn').attr('src', '../Data/Wishes/' + result).show();

                    HideLoading();
                },
                error: function(err) {
                    alert(err.statusText);
                    HideLoading();
                }
            });
        } else {
            alert("FormData is not supported.");
        }

    }
Beastly answered 11/9, 2018 at 9:43 Comment(1)
Welcome to Stack Overflow! Please don't answer just with source code. Try to provide a nice description about how your solution works. See: How do I write a good answer?. ThanksYarborough

© 2022 - 2024 — McMap. All rights reserved.