84

I require to generate a thumbnail of an image in my web application. I make use of the HTML5 File API to generate the thumbnail.

I made use of the examples from Read files in JavaScript to generate the thumbnails.

I am successfully able to generate the thumbnails, but I am able to generate thumbnail only by using a static size. Is there a way to get the file dimensions from the selected file and then create the Image object?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Abishek
  • 11,191
  • 19
  • 72
  • 111
  • Useful link: http://stackoverflow.com/questions/12570834/how-to-preview-image-get-file-size-image-height-and-width-before-upload/12570870#12570870 – Roko C. Buljan Nov 10 '14 at 06:55

4 Answers4

160

Yes, read the file as a data URL and pass that data URL to the src of an Image: http://jsfiddle.net/pimvdb/eD2Ez/2/.

var fr = new FileReader;

fr.onload = function() { // file is loaded
    var img = new Image;

    img.onload = function() {
        alert(img.width); // image is loaded; sizes are available
    };

    img.src = fr.result; // is the data URL because called with readAsDataURL
};

fr.readAsDataURL(this.files[0]); // I'm using a <input type="file"> for demonstrating
pimvdb
  • 151,816
  • 78
  • 307
  • 352
  • 10
    `img.onload = function() {` never triggers – Alex G Oct 07 '16 at 17:05
  • 2
    do `img.src = fr.result;` before `img.onload` – bershika Jan 14 '18 at 04:19
  • 6
    `img.onload` is the handler for the `onload` event on the `Image` and will only be called after something is loaded. In this case `img.src = fr.result;` will trigger the `onload` event. Semantically you would want your event handler bound before your event could possibly fire. If the `onload` is not firing, then try `img.onerror = function(err) { console.error(err); }` to see if the file reader failed to load something that `Image` can handle. (or if something else went wrong) – wolfram42 Nov 15 '18 at 20:31
40

Or use an object URL: http://jsfiddle.net/8C4UB/

var url = URL.createObjectURL(this.files[0]);
var img = new Image;

img.onload = function() {
    alert(img.width);
    URL.revokeObjectURL(img.src);
};

img.src = url;
whirish
  • 450
  • 4
  • 18
letmaik
  • 3,348
  • 1
  • 36
  • 43
  • 5
    This approach doesn't load the image into memory. readAsDataURL does. http://stackoverflow.com/questions/6217652/html5-file-api-crashes-chrome-when-using-readasdataurl-to-load-a-selected-image – Isius Dec 18 '13 at 22:08
  • 5
    Generally it's best to revoke url in the `onload` handler: `URL.revokeObjectURL(url)`. – x-yuri Feb 12 '19 at 09:00
31

The existing answers helped me a lot. However, the odd order of events due to the img.onload event made things a little messy for me. So I adjusted the existing solutions and combined them with a promise-based approach.

Here is a function returning a promise with the dimensions as an object:

const getHeightAndWidthFromDataUrl = dataURL => new Promise(resolve => {
  const img = new Image()
  img.onload = () => {
    resolve({
      height: img.height,
      width: img.width
    })
  }
  img.src = dataURL
})

Here is how you could use it with an async function:

// Get a file from an input field
const file = document.querySelector('[type="file"]').files[0]

// Get the data URL of the image as a string
const fileAsDataURL = window.URL.createObjectURL(file)

// Get dimensions
const someFunction = async () => {
  const dimensions = await getHeightAndWidthFromDataUrl(fileAsDataURL)
  // Do something with dimensions ...
}

And here is how you could use it using the then() syntax:

// Get a file from an input field
const file = document.querySelector('[type="file"]').files[0]

// Get the data URL of the image as a string
const fileAsDataURL = window.URL.createObjectURL(file)

// Get the dimensions
getHeightAndWidthFromDataUrl(fileAsDataURL).then(dimensions => {
  // Do something with dimensions
})
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sam
  • 1,711
  • 1
  • 17
  • 24
5

I have wrapped pimvdb's answer in a function for general-purpose use in my project:

function checkImageSize(image, minW, minH, maxW, maxH, cbOK, cbKO) {
    // Check whether browser fully supports all File API
    if (window.File && window.FileReader && window.FileList && window.Blob) {
        var fr = new FileReader;
        fr.onload = function() { // File is loaded
            var img = new Image;
            img.onload = function() { // The image is loaded; sizes are available
                if(img.width < minW || img.height < minH || img.width > maxW || img.height > maxH) {
                    cbKO();
                } else {
                    cbOK();
                }
            };
            img.src = fr.result; // Is the data URL because called with readAsDataURL
        };
        fr.readAsDataURL(image.files[0]);
    } else {
        alert("Please upgrade your browser, because your current browser lacks some new features we need!");
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Necrontyr
  • 171
  • 3
  • 2