blueimp / JavaScript-Load-Image

Load images provided as File or Blob objects or via URL. Retrieve an optionally scaled, cropped or rotated HTML img or canvas element. Use methods to parse image metadata to extract IPTC and Exif tags as well as embedded thumbnail images, to overwrite the Exif Orientation value and to restore the complete image header after resizing.
https://blueimp.github.io/JavaScript-Load-Image/
MIT License
4.45k stars 924 forks source link

loadImage firing callback multiple times in Firefox #29

Closed vishalsood closed 11 years ago

vishalsood commented 11 years ago

I am using Firefox 22.0 and I am noticing that loadImage callback is firing multiple times causing issues. This does not happen in Chrome.

Am I doing something wrong?

I am just calling, load image inside a drop handler if (!loadImage( imageFile, that._loadImageSuccess )) { //TODO: Handle failure case
}

Thanks a lot! Vishal

blueimp commented 11 years ago

I'm sorry but I could not reproduce such an issue, nor am I aware of any similar reports. Maybe there is another part of your code that is causing this issue. I'm closing this issue for now, feel free to reopen if you can definitely track down this issue as a bug of this library.

vishalsood commented 11 years ago

Thanks, I am definitely seeing it. I traced back to loadImage call I do in the code and then I get multiple callbacks. Would you be willing to look at a live repro?

vishalsood commented 11 years ago

I actually saw the following error messages on the console. Does this give any hints? I'll keep debugging otherwise.

Looks like in the method - loadImage.renderImageToCanvas.

[19:39:11.113] TypeError: Value could not be converted to any of: HTMLImageElement, HTMLCanvasElement, HTMLVideoElement. @ http://localhost:8001/js/libs/load-image.js:147

[19:42:00.187] TypeError: Value could not be converted to any of: HTMLImageElement, HTMLCanvasElement, HTMLVideoElement. @ http://localhost:8001/js/libs/load-image.js:147 [19:42:01.257] TypeError: Value could not be converted to any of: HTMLImageElement, HTMLCanvasElement, HTMLVideoElement. @ http://localhost:8001/js/libs/load-image.js:147 [19:48:17.879] TypeError: Value could not be converted to any of: HTMLImageElement, HTMLCanvasElement, HTMLVideoElement. @ http://localhost:8001/js/libs/load-image.js:147

blueimp commented 11 years ago

Could you provide a reproducible demo on JSFiddle? http://jsfiddle.net/ Please try to isolate the problem as much as possible, that is, if possible, only include the absolutely necessary code to reproduce the problem.

dillpixel commented 11 years ago

We're experiencing the same issue. The callback is fired multiple times in Firefox only (Chrome works fine).

blueimp commented 11 years ago

Please refer to my comment above.

dillpixel commented 11 years ago

I could not reproduce the error in jsfiddle either... however I was able to address this issue in my environment by using the noRevoke flag.

I traced the double callback to an error occuring within the img.onload function triggering the img.onerror function and both functions resulting callback.

So it seems that an issue in my code is causing an error in load-image after the image has already been loaded which results in a double callback.

blueimp commented 11 years ago

Thanks for reporting back.

dillpixel commented 11 years ago

I believe this is actually being caused by a synchronization issue which seems to apply only to Firefox. Since our application is non-trivial, it's difficult for us to reproduce the error in a simple test case. However, we were able to fix this by making a slight modification to your code. We simply swapped the if statements in the img.onload function:

Old Code

img.onload = function () {
  if (oUrl && !(options && options.noRevoke)) {
    loadImage.revokeObjectURL(oUrl);
  }
  if (callback) {
    callback(loadImage.scale(img, options));
  }
};

New Code

img.onload = function () {
  if (callback) {
    callback(loadImage.scale(img, options));
  }
  if (oUrl && !(options && options.noRevoke)) {
    loadImage.revokeObjectURL(oUrl);
  }
};

We're still not sure exactly why this solves our issue, but we figured it might be helpful to others.

blueimp commented 11 years ago

Instead of switching those statements, you should rather set the noRevoke option to true, as you have stated yourself in a previous comment.

By default, the created ObjectURL is revoked as soon as the img has been loaded. I guess in your application, the img element is somehow forced to reload its source and then fires an error, since the img src is not available anymore.

dillpixel commented 11 years ago

noRevoke works great, the behavior you are describing is exactly what happened. Thanks for the quick reply.

vishalsood commented 11 years ago

Thank you very much. The setting of noRevoke solved my issues too.

brodock commented 11 years ago

Here is an example fiddle with the problem: http://jsfiddle.net/cbfranca/y9qvJ/2/

blueimp commented 11 years ago

Don't use .html(), use .append() to add the image to your container and you won't have a problem: http://jsfiddle.net/y9qvJ/4/

loadImage returns an image element, which you can directly append. With .html() you will instead force a reload if the image.