Get width height of remote image from url
Asked Answered
B

6

101

So the alert gives undefined values for the width and height. I think the w and h values of the image from the img.onload calculation is not being passed to the values to return, or it may be returning w and h before the onload calculates them:

function getMeta(url){
 var w; var h;
 var img=new Image;
 img.src=url;
 img.onload=function(){w=this.width; h=this.height;};
 return {w:w,h:h}    
}

// "http://snook.ca/files/mootools_83_snookca.png" //1024x678
// "http://shijitht.files.wordpress.com/2010/08/github.png" //128x128

var end = getMeta("http://shijitht.files.wordpress.com/2010/08/github.png");
var w = end.w;
var h = end.h;
alert(w+'width'+h+'height');

How can I have the alert show the correct width and height?

http://jsfiddle.net/YtqXk/

Booklover answered 11/7, 2012 at 22:51 Comment(1)
The reason it's not working is because at the point when you return your width and height values they are not yet known. You need to deal with the result inside the onload callback. You should probably make the callback function a second argument to your getMeta function.Undervest
D
172

Get image size with JavaScript

In order to read the data from an image you'll need to make sure it's first loaded. Here's a callback-based approach and two promise-based solutions:

Callback

const getMeta = (url, cb) => {
  const img = new Image();
  img.onload = () => cb(null, img);
  img.onerror = (err) => cb(err);
  img.src = url;
};

// Use like:
getMeta("https://i.stack.imgur.com/qCWYU.jpg", (err, img) => {
  console.log(img.naturalWidth, img.naturalHeight);
});

Using the load Event listener (Promise):

const getMeta = (url) =>
  new Promise((resolve, reject) => {
    const img = new Image();
    img.onload = () => resolve(img);
    img.onerror = (err) => reject(err);
    img.src = url;
  });

// Usage example: 
;(async() => {
  const img = await getMeta('https://i.stack.imgur.com/qCWYU.jpg');
  console.dir(img.naturalHeight + ' ' + img.naturalWidth);
})();

Using HTMLImageElement.decode() (Promise)

const getMeta = async (url) => {
  const img = new Image();
  img.src = url;
  await img.decode();  
  return img
};

// Usage example:
getMeta('https://i.stack.imgur.com/qCWYU.jpg').then(img => {
  console.dir(img.naturalHeight +' '+ img.naturalWidth);
});
Dahl answered 11/7, 2012 at 23:7 Comment(6)
Since the width and height are not being returned, how can I have them returned to use outside the function?Booklover
@Booklover not without calling some function inside the .load function --- or a setInterval, cause while your code is readed and executed, the image is still loading: Interval will check till the image is loaded and clear it self like in this demo: jsfiddle.net/roXon/SN2t6/1Dahl
@Booklover look at here for call a function as soon the image is loaded : jsfiddle.net/roXon/SN2t6/4Dahl
Note that the width and height come back as 0 for SVG images in IE11Dys
@RokoC.Buljan, a code from the jQuery section throws the error: Uncaught TypeError: url.indexOf is not a function. I think a little mistake creep into it, namely img attribute and listener are landed in the same object. see this answerChristoforo
This comes back with a CORS error if not on the same origin - even with img.crossOrigin=true added. Is there a way to change the MIME type of this request or otherwise add headers to a pure JPG request?Ectoenzyme
V
35

Just pass a callback as argument like this:

function getMeta(url, callback) {
    const img = new Image();
    img.src = url;
    img.onload = function() { callback(this.width, this.height); }
}
getMeta(
  "http://snook.ca/files/mootools_83_snookca.png",
  (width, height) => { alert(width + 'px ' + height + 'px') }
);
Valente answered 13/10, 2014 at 12:2 Comment(2)
Thanks, this is help me a lot.Fie
Note that the width and height come back as 0 for SVG images in IE11Dys
A
28

ES6

Using async/await you can do below getMeta function in sequence-like way and you can use it as follows (which is almost identical to code in your question (I add await keyword and change variable end to img, and change var to let keyword). You need to run getMeta by await only from async function (run).

function getMeta(url) {
    return new Promise((resolve, reject) => {
        let img = new Image();
        img.onload = () => resolve(img);
        img.onerror = () => reject();
        img.src = url;
    });
}

async function run() {

  let img = await getMeta("http://shijitht.files.wordpress.com/2010/08/github.png");

  let w = img.width;
  let h = img.height; 

  size.innerText = `width=${w}px, height=${h}px`;
  size.appendChild(img);
}

run();
<div id="size" />

Rxjs

const { race, fromEvent, map, mergeMap, of } = rxjs;

function getMeta(url) {
    return of(url).pipe(
        mergeMap((path) => {
            const img = new Image();
            let load = fromEvent(img, 'load').pipe(map(_=> img))
            let error = fromEvent(img, 'error').pipe(mergeMap((err) => throwError(() => err)));
            img.src = path;
            
            return race(load, error);
        })
    );
}


let url = "http://shijitht.files.wordpress.com/2010/08/github.png";

getMeta(url).subscribe(img=> { 
  let w = img.width;
  let h = img.height; 

  size.innerText = `width=${w}px, height=${h}px`;
  size.appendChild(img);
}, e=> console.log('Load error'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/7.5.2/rxjs.umd.min.js" integrity="sha512-wBEi/LQM8Pi08xK2jwHJNCiHchHnfcJao0XVQvkTGc91Q/yvC/6q0xPf+qQr54SlG8yRbRCA8QDYrA98+0H+hg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

<div id="size" />
Apparatus answered 27/6, 2018 at 13:18 Comment(1)
Thank you. I used Promise.all() to get all values at once.Rhiannonrhianon
E
13

The w and h variables in img.onload function are not in the same scope with those in the getMeta() function. One way to do it, is as follows:

Fiddle: http://jsfiddle.net/ppanagi/28UES/2/

function getMeta(varA, varB) {
    if (typeof varB !== 'undefined') {
       alert(varA + ' width ' + varB + ' height');
    } else {
       var img = new Image();
       img.src = varA;
       img.onload = getMeta(this.width, this.height);
    }
}


getMeta("http://snook.ca/files/mootools_83_snookca.png");
Extrasystole answered 11/7, 2012 at 23:10 Comment(8)
Thanks, this works as intended, just takes a bit too long to get the infoBooklover
This solution will not work if the image has not already been stored in the browser's cache. You must accept a callback function in getMeta that will be called when the onload event fires (jsfiddle.net/28UES)Accordance
@Zack hmmm.. Since the width and height are not being returned, how can I have them returned to use outside the function?Booklover
@Booklover updated my answer. As soon as you define a callback function you can pass it the variables and manipulate them in the callback function.Extrasystole
@Zack I see the update, which resolves the cache issue. But can you show how to access the width and height outside the function. I need the function to return values outside of itself.Booklover
@Booklover It's not possible to know the width and height of an image until after it has been downloaded. This occurs asynchronously (#2691801), so the getMeta function cannot return the dimensions directly. The usual workaround is to pass a callback function to getMeta that does something useful with the dimensions after the image has been loaded.Accordance
Any code outside the getMeta() function will be called before the dimensions of the image are available. Therefore, as Ferri points out, you need to use a callback function for the onload event of the image.Extrasystole
this is recursive function (function which call itself)Pau
C
0

Get image size with jQuery
(depending on which formatting method is more suitable for your preferences):

function getMeta(url){
    $('<img/>',{
        src: url,
        on: {
            load: (e) => {
                console.log('image size:', $(e.target).width(), $(e.target).height());
            },
        }
    });
}

or

function getMeta(url){
    $('<img/>',{
        src: url,
    }).on({
        load: (e) => {
            console.log('image size:', $(e.target).width(), $(e.target).height());
        },
    });
}
Christoforo answered 16/5, 2020 at 21:47 Comment(0)
E
-2

You will can try package.

import getImageSize from 'image-size-from-url';

const {width, height} = await getImageSize('URL');
Eurystheus answered 12/8, 2022 at 20:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.