Oscar Godson
Oscar Godson

Reputation: 32726

onload is not firing with createObjectURL img.src in Firefox

I have the following code. It works totally fine, and as expected, in Chrome. However, in Firefox it logs "CONVERT" but never "LOADED". No JS errors or anything. onload just doesn't fire. I can't seem to find much on google or stackoverflow. Many say onload doesn't fire for cached images, but these shouldn't be cached and even if they were, I wouldnt be able to cache bust them (right?)

  flattenImage: function(file, callback){
    // Safari uses webkitURL
    var URL = window.URL || window.webkitURL;
    var canPreformat = !!(window.Blob && window.Uint8Array && URL && URL.createObjectURL);

    // If we have all features we need to preformat on the client and the image
    // isn't already flattened (jpeg), DO IT
    if (canPreformat && !file.type.test(/jpe?g/i)) {
      console.log('CONVERT');
      var thiz = this;
      var c = document.createElement('canvas');
      var ctx = c.getContext('2d');
      var img = new Image;
      // Makes a blob URL from the file given.
      img.onload = function() {
        console.log('LOADED');
        c.width = this.width;
        c.height = this.height;

        // Take the img that was added and copy it to the canvas
        ctx.drawImage(img, 0, 0);

        // Put the image on top of everything else
        ctx.globalCompositeOperation = 'destination-atop';

        // Any transparency should become white (instead of the default black)
        ctx.fillStyle = "#fff";
        ctx.fillRect(0, 0, this.width, this.height);

        // Save canvas as a base64'd jpeg
        var dataURL = c.toDataURL("image/jpeg");

        // The following blob lines take the base64 encoded image and then
        // convert it to a jpeg "file". This allows us to do a real file
        // upload rather than needing to send a base64 string.
        var blobBin = atob(dataURL.split(',')[1]);
        var array = [];
        for(var i = 0; i < blobBin.length; i++) {
          array.push(blobBin.charCodeAt(i));
        }
        callback.call(thiz, new Blob([new Uint8Array(array)], {type: 'image/jpeg'}));
      }
      img.src = URL.createObjectURL(file);
    }
    // If we don't have all the features just return the same file given to us
    else {
      console.log('NOPE')
      callback.call(this, file);
    }
  }

Upvotes: 4

Views: 2768

Answers (1)

Oscar Godson
Oscar Godson

Reputation: 32726

I got around this issue by not using createObjectURL and instead use FileReader like this:

flattenImage: function(file, callback){
    // Safari uses webkitURL
    var URL = window.URL || window.webkitURL;
    var canPreformat = !!(window.FileReader && window.Blob && window.Uint8Array);

    // If we have all features we need to preformat on the client and the image
    // isn't already flattened (jpeg), DO IT
    if (canPreformat && !file.type.test(/jpe?g/i)) {
      console.log('CONVERT');
      var thiz = this;
      var c = document.createElement('canvas');
      var ctx = c.getContext('2d');

      var reader = new FileReader();
      var img = new Image;

      // Once the image is loaded from FileReader set the src of the image to
      // the base64'd result. This will trigger the img.onload
      reader.onload = function (ev) {
        img.src = ev.target.result;
      };

      // Makes a blob URL from the file given.
      img.onload = function() {
        console.log('LOADED');
        c.width = this.width;
        c.height = this.height;

        // Take the img that was added and copy it to the canvas
        ctx.drawImage(img, 0, 0);

        // Put the image on top of everything else
        ctx.globalCompositeOperation = 'destination-atop';

        // Any transparency should become white (instead of the default black)
        ctx.fillStyle = "#fff";
        ctx.fillRect(0, 0, this.width, this.height);

        // Save canvas as a base64'd jpeg
        var dataURL = c.toDataURL("image/jpeg");

        // The following blob lines take the base64 encoded image and then
        // convert it to a jpeg "file". This allows us to do a real file
        // upload rather than needing to send a base64 string.
        var blobBin = atob(dataURL.split(',')[1]);
        var array = [];
        for(var i = 0; i < blobBin.length; i++) {
          array.push(blobBin.charCodeAt(i));
        }
        callback.call(thiz, new Blob([new Uint8Array(array)], {type: 'image/jpeg'}));
      }
      reader.readAsDataURL(file);
    }
    // If we don't have all the features just return the same file given to us
    else {
      callback.call(this, file);
    }
  }

Upvotes: 3

Related Questions