0

I was wondering if it was possible to get the width and height of an image without putting an image into page, i.e without creating an image tag that displays it.

trying to make a sprite class using this method.

function Sprite(src,frames) {
    // Sprite class 
    this.img = new Image();
    this.img.src = src;

    this.frames = frames;
    this.cframe = 1;

    this.setDim = function() {
      this.fullWidth = this.img.width;
      this.fullHeight = this.img.height;
    }

    this.img.onload = this.setDim();
    console.log(this.fullWidth);
    return this;
  }

however this.fullWidth returns undefined and the below that ignores the onload returns 0

 function Sprite(src,frames) {
    // Sprite class 
    this.img = new Image();
    this.img.src = src;

    this.frames = frames;
    this.cframe = 1;

    this.fullWidth = this.img.width;
    this.fullHeight;

    this.setDim = function() {
      this.fullWidth = this.img.naturalWidth;
      this.fullHeight = this.img.height;
      console.log(this.fullWidth)
    }
    console.log(this.fullWidth)
    //this.img.onload = this.setDim();

    return this;
  }

I don't really want to use Jquery for this. I have also tried this.img.natrualWidth (as you can see in the example above) it also returns 0

Any advice would be great, Thanks

Updated this to match @vihan1086 answer

      function Sprite(src,frames) {
    // Sprite class 
    this.img = new Image();
    this.img.src = src;

    this.frames = frames;
    this.cframe = 1;

    var self = this;
    self.loaded = function () {};
    this.setDim = function() {

      self.fullWidth = this.width;
      self.fullHeight = this.height;

      self.frameWidth = this.width / self.frames;
      self.frameHeight = this.height;

      self.loaded.apply(self, []);
    }

    this.loaded = function() {
      return this;
    }

    this.img.onload = this.setDim;

  }

then use

sprite = new Sprite(sprite,5);
    sprite.loaded = function() {
      console.log(sprite.fullWidth);

    }
mikey
  • 50
  • 7
  • 1
    `this.img.onload = this.setDim(); console.log(this.fullWidth);` You are setting an event listener and immediately afterwards checking the value, before the event even fired. – Sebastian Simon Apr 06 '15 at 21:56
  • you could make the image non visible. but guess thats not what you want right? you dont want to even load the image. – btevfik Apr 06 '15 at 21:56
  • 1
    `this.img.onload = this.setDim()` should be `this.img.onload = this.setDim` (pass the function reference, don't call it.) – JJJ Apr 06 '15 at 21:57

2 Answers2

0

Problem

var img = new Image();
img.src = '/my/src/to/file';

//this refers to the current function at this point

img.onload = function () {
   //this is 'img' at this point not the function
}

Solution

this is not in scope so you would add:

var self = this;//Self and this are referring to the same thing, the function

img.onload = function () {
    //this refers to image but self still refers to the function's this
    self.width = this.width;
    self.height = this.height;
}

console.log(this.width);//logs width
console.log(this.height);//logs height

This leaves async problems which can be solved using two methods

A

this.img.onload = this.setDim; //Noticed the dropped ()

B

self.loaded = function () {};

this.setDim = function () {
    //...
    self.loaded.apply(self, []);
}

then

var sprite = new Sprite(...);
sprite.loaded = function () {
    console.log(this.fullHeight);
}

Explanation

img.onload() changes the scope of the code, resulting in your this referring to img. Now the weird part. We created a variable self which refers to this, this allows us to refer to this in a different scope by using self.

Other

img.onload is "async" which means it won't follow along with the rest of the code. This means the console.log() has run, but the img.onload hasn't. Be careful when working when this type of code (I wrote a few solutions in the update). You should wait until img.onload is finished before checking the values. I've worked on something like this before and I'll see if I can find what I did to address all these issues; if I can, I'll update this answer.

UPDATE: I wouldn't run the setDim function at first and let the user run it setDim() -> setDim. If you wish to load the dimensions at first, put a load function to your Sprite() which is run when the dimensions are retrieved.

Downgoat
  • 13,771
  • 5
  • 46
  • 69
  • is that different from what I am doing in the first example? please correct me if I am wrong – mikey Apr 06 '15 at 21:58
  • that's ok thanks, I understand what I was doing wrong. I was still trying to get the values before the image was loaded, and as @Juhana said i was calling the function instead of passing it – mikey Apr 06 '15 at 22:09
  • i added a example, something like that? – mikey Apr 06 '15 at 22:20
  • @mikey in your answer, use `self.load.apply(self, []);` instead of `self.load();` and put `console.log(sprite.fullWidth);` inside a `sprite.load=function(){}` – Downgoat Apr 06 '15 at 22:27
0

In javascript the statements are executed asynchronously. To know more about this read this excellent article Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference

In your case as @Juhana mentioned passing reference should get the issue resolved

Community
  • 1
  • 1
meteor
  • 2,518
  • 4
  • 38
  • 52