200

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?

SandroMarques
  • 6,070
  • 1
  • 41
  • 46
Simon
  • 5,070
  • 5
  • 33
  • 59

11 Answers11

281

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.

Amirhossein Mehrvarzi
  • 18,024
  • 7
  • 45
  • 70
Esailija
  • 138,174
  • 23
  • 272
  • 326
  • 1
    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 ago – Seho Lee Nov 28 '12 at 11:59
  • 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 (http://caniuse.com/#search=file%20api) – Michael Yagudaev Sep 18 '13 at 23:24
  • 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. – Wisarut Bholsithi Feb 25 '22 at 17:50
  • Content Security Policy prevent this solution – Mehdi Oct 17 '22 at 01:38
78

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;
  };
};
idkwhatsgoingon
  • 658
  • 4
  • 22
ash das
  • 887
  • 7
  • 11
  • 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 errors – Felipe Apr 23 '21 at 00:46
  • 1
    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. – Avatar Jan 24 '22 at 16:23
  • @Avatar you should state who posted the top answer, since the top answer changes over time. – constantlyFlagged Feb 12 '22 at 15:05
  • Good point. The answer I mean: https://stackoverflow.com/a/8904008/1066234 – Avatar Feb 13 '22 at 10:49
43

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";
pseudosavant
  • 7,056
  • 2
  • 36
  • 41
  • what about when you need them specifically prior to load for aspect ratio calculations to prevent cumulative layout shift – nrmad Aug 02 '22 at 10:41
35

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.`);
   }                
}
Eric Wallen
  • 651
  • 7
  • 7
  • 2
    Remember to call URL.revokeObjectURL() to avoid memory leaks. https://developer.mozilla.org/en-US/docs/Web/API/URL/revokeObjectURL – squirtgun Dec 20 '22 at 21:00
6

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)
}
E G
  • 498
  • 6
  • 7
5

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;
        }
    }
Ir Calif
  • 460
  • 6
  • 7
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;
        }
    }
Jose Fdo
  • 91
  • 2
  • 8
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;
    }
}
Wayne Smallman
  • 1,690
  • 11
  • 34
  • 56
Shahbaz Raees2
  • 201
  • 2
  • 5
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.

Amirhossein Mehrvarzi
  • 18,024
  • 7
  • 45
  • 70
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);
Dharman
  • 30,962
  • 25
  • 85
  • 135
Loïc Boset
  • 343
  • 3
  • 13
-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.");
        }

    }
TJBlackman
  • 1,895
  • 3
  • 20
  • 46
Shahbaz Raees2
  • 201
  • 2
  • 5
  • 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?](https://stackoverflow.com/help/how-to-answer). Thanks – sɐunıɔןɐqɐp Sep 11 '18 at 10:01