Get width height of remote image from url

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/


Solution 1:

Get image size with jQuery

function getMeta(url) {
    $("<img/>",{
        load: function() {
            alert( this.width +" "+ this.height );
        },
        src: url
    });
}

Get image size with JavaScript

function getMeta(url) {   
    var img = new Image();
    img.onload = function() {
        alert( this.width +" "+ this.height );
    };
    img.src = url;
}

Get image size with JavaScript (modern browsers, IE9+ )

function getMeta(url){   
    const img = new Image();
    img.addEventListener("load", function() {
        alert( this.naturalWidth +' '+ this.naturalHeight );
    });
    img.src = url;
}

Use like: getMeta( "http://example.com/img.jpg" );

https://developer.mozilla.org/en/docs/Web/API/HTMLImageElement

Solution 2:

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') }
);

Solution 3:

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" />

Solution 4:

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");